code flow in rackt react-router - reactjs-flux

I am having difficulty knowing the flow of react-router by (https://github.com/rackt/react-router).
If i have 2 files: routes.js, app.js(entry component) as below:
var Router = require('react-router');
var Route = Router.Route;
var routes = (
<Route handler={App}>
<Route path="/" handler={home}/>
</Route>
);
module.exports = routes;
app.js
var React = require('react');
var Router = require('../routes.js');
var RouteHandler = Router.RouteHandler;
var App= React.createClass({
render: function(){
return (
<RouteHandler/>
)
}
});
module.exports = App;
How does the app component gets called? As of traditional way i use following code to render "app" component in app.js.
React.render(
<App />, document.getElementById('main')
);
Now what i dont understand is what is the following code doing. Is it replacement of traditional way of rendering, i need to use following code to listen to url and render app.js but not the above code?
Router.run(routes, Router.HashLocation, (Root) => {
React.render(<Root/>, document.body);
});
What if i am using another js file "main.js" to render "app.js" and now i want to use app.js to handle all the route how do i do it. Mean to say i want to render what ever the route is passed in app.js.
My code in main.js is below:
React.render(
<APP />, document.getElementById('main')
);

First off, you need to update your App.js file to grab the correct react-router module. You're assigning the export of your routes.js file to Router, but it should be react-router. Node will actually cache the result of the module and reuse it for every other reference to it.
Your approach would work ok -- typically you see something like a Main.js file to handle the routing, and the App.js is more of the wrapper for your component(s).
So I would make a Main.js file like so..
// Main.js
var React = require('react');
var Router = require('react-router');
var routes = require('../routes.js');
var RouteHandler = Router.RouteHandler;
Router.run(routes, function(Handler, state) {
React.render(<Handler />, document.body);
});
Then, just make your App.js mount the RouteHandler and handle any other parent state. When you navigate to the route, it will match it in the Router.run function and then all routes in the 'family' of the matched route will be rendered.

Related

laravel passing a variable to js file from a controller

I have a js file located in assets folder (not View). can i pass a varible from a controller?
In view file:
The Js is called like this
<canvas id="chart1" class="chart-canvas"></canvas>
</div>
It is not possible (in my point of view) to put a variable to external JS file. You can use data-... attributes and get values from html elements.
For example you can pass your PHP variable as a json encoded string variable in your controller.
$data['chart_info'] = json_encode($chart_info);
return view('your_view', $data);
Then put it in data-info like this.
<canvas id="chart1" class="chart-canvas" data-info="{{ $chart_info }}"></canvas>
And finally in JS, you can get the variable and decode (parse) it as following.
let canvas = document.getElementById('chart1');
let info = JSON.parse(canvas.dataset.id);
console.log(info);
You can put that part of the Javascript in the view and send the variable to the same view. For example, add a section in view:
#section('footer')
<script type="text/javascript">
</script>
#endsection
Do not forget that you should add #yield('footer') to the end of your layout view.
I don't like to mix javascript and PHP/Blade, it might be hard to read the code in the future... You could use a different approach, loading the chart with a async ajax request.
You will have to create a end-point that returns the data you need for your chart:
Your router:
Route::get('/chart/get-data', [ ControllerName::class, 'getChartData' ]);
Your controller method:
public function getChartData() {
$chartData = [];
// Your logic goes here
return $chardData;
}
In your javascript (using jquery) file there will be something like that:
function loadChartData() {
$.ajax({
'url': '/chart/get-data',
'method': 'GET'
})
.done((data) => {
// Load your chart here!!!
})
.fail(() => {
console.log("Could not load chart data");
});
}
Hope I helped ;)

Laravel + SPA VueJs not giving error for unknown component

<template>
<div>
<test-component />
</div>
</template>
<script>
//import TestComponent from '../path-to-components/TestComponent';
export default {
name: 'SomeRandomComponent',
components: {
TestComponent,
}
}
</script>
Expected Behaviour:
The application should give some console error if there is a problem with the imports or anything else similar to this.
Current Behaviour:
The page get blank in the browser and there is no error in console even if the import statement is commented out.
Code for reference
app.js
import Vue from 'vue';
import router from '~/router';
import App from '~/components/App';
new Vue({
router,
...App
})
router.js
export default [
{ path: '/some-path', name: 'testing', component: import( `~/pages/path-to-component`).then(m => m.default || m) },
]
App.vue
<template>
<div id="app">
<loading ref="loading" />
<transition name="page" mode="out-in">
<component :is="layout" v-if="layout" />
</transition>
</div>
</template>
<script>
import Loading from './Loading'
// Load layout components dynamically.
const requireContext = require.context('~/layouts', false, /.*\.vue$/)
const layouts = requireContext.keys()
.map(file =>
[file.replace(/(^.\/)|(\.vue$)/g, ''), requireContext(file)]
)
.reduce((components, [name, component]) => {
components[name] = component.default || component
return components
}, {})
export default {
el: '#app',
components: {
Loading
},
data: () => ({
layout: null,
defaultLayout: 'default'
}),
metaInfo () {
const { appName } = window.config
return {
title: appName,
titleTemplate: `%s ยท ${appName}`
}
},
mounted () {
this.$loading = this.$refs.loading
},
methods: {
/**
* Set the application layout.
*
* #param {String} layout
*/
setLayout (layout) {
if (!layout || !layouts[layout]) {
layout = this.defaultLayout
}
this.layout = layouts[layout]
}
}
}
</script>
I am assuming that you are using Vue2 since Vue3 is in beta.
The first problem I see with your code, is that your <div id="app"> is inside a Vue component.
Declarative Rendering
What happening is that everything is compile, but you are trying to render Vue inside a component that does not exist.
Instead, create a div element inside the html or blade.php file that is loaded by the client. For my part, I use a blade layout like this:
//resources/views/layouts/app.blade.php
...
</head>
<body>
<div id="app" v-cloak> //This is plain loaded when client render views, then, when script will initiate, Vue will be able to access everything inside this.
<navbar v-bind:core="core"></navbar> //There is my navbar which is a Vue component.
<div class="boxed">
<div id="content-container">
#yield('content') //Blade component are injected there. since it's inside the <div id="app">, thoses component can include Vue directive/component.
</div>
...
Another thing that seems a problem is that you are initiating Vue inside a Vue component. Things are that Vue is a package and compiled into javascript in the end. But, to make all the magic happen, you need to have somwhere to initiate all this. In that case, your App.js file should look something like this:
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app',
});
This file is the one created by default by laravel for Vue template on fresh Laravel 8 install.
The difference between import and require is that import create a promise.
You don't want a promise there, because you want that file to be execute at the moment the client will begin to render your page.
Following thoses recommendation, I think you will be able to get your app working quickly and Vue will start logging error into your console.

Building a Laravel MPA with Blade, but adding Vue to some pages [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am developing a classic MPA webpage using Laravel and Blade templates.
But in some of the pages, I would like to add some reactivity to improve the user experiencie, using the Vue framework for that.
So far so good, if I import Vue and JS code in a normal script tag at the end of the corresponding blade templates, I get it done.
But my problem is that I need all the JS code to be minified and processed by webpack (Laravel Mix) so that javascript source is not exposed.
Any ideas?
Thanks in advance.
If you ran the following artisan commands to install Vue in Laravel:
composer require laravel/ui
php artisan ui vue
your app.js file which comes standard with Laravel will have been updated automatically to import Vue. It will look something like this (but with comments):
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
const app = new Vue({
el: '#app',
});
So with that, you could begin creating Vue components for different sections of your website.
However, if your issue is that you want to have multiple different Vue instances throughout your application based on the page, you would begin by taking the same layout as the code block above (minus the bootstrap require statement) and choose a different element id for the new instance. Then you would create a new Javascript file to house the specific components/functions you desire and add them to your webpack.mix.js like this:
mix.js('resources/js/app.js', 'public/js') // old line
.js('resources/js/header/header.js', 'public/js') // additional line
then in your blade file, you would simply use the new script like so:
<script src="{{ asset('js/header.js') }}"></script>
Edit: Based on Comment
Probably the easiest way to pass the data from your blade file to the specific Vue instance would be to prop the data on the element the Vue instance is initiated one (comparable to propping a blade variable through to a Vue component as well). If this was your element:
const app = new Vue({
el: '#show-order',
});
You could prop the id of the order ($id needs passed from the controller/view)
<div id="show-order" order_id="{{ $id }}">
...
</div>
Then you set up the prop within the Vue instance:
const app = new Vue({
el: '#show-order',
props: ['order_id'],
});
and maybe used in a method like so:
const app = new Vue({
el: '#show-order',
props: ['order_id'],
methods: {
logMyProp: function() {
console.log(this.order_id);
}
}
});
Alternatively you could create a method within your instance that's responsible for calling a method that loads the data directly into the instance instead of passing the data from the controller => blade => vue component.
...
data: function() {
return {
order: {},
}
},
methods: {
loadMyData: function() {
let vm = this;
$.ajax({
url: '/orders/load/'
}).done(function(response) {
vm.order = response;
});
}
},
...

Laravel Vue js : How can I update a component form Javascript like this:

in my blade.php use one component
<loading :prop_show_loading="show_loading"></loading>
Still in my blade.php
This Doesn't work
<script>
var show_loading = true;
</script>
this Does't work too
<script>
window.event = new Vue();
window.event.$emit('prop_show_loading', 'true');
</script>
and my component doing this (window is not defined)
created(){
let App = this;
console.log(global.event);
window.event.$on('close-modal', (event) => {
this.prop_show_loading = true;
})
},
Any idea?
if you need pass the prop_show_loading value from laravel to loading vue component.
you don't use ":" in the head:
<loading prop_show_loading="show_loading"></loading>
and in the loading component use:
export default {
props: ['prop_show_loading'],
...
and than you can use this.prop_show_loading to get the value.

does ui router not work in jade?

I am setting up a simple crud app. However, I am not sure what is going on with ui-router. I read that you should use html tags so I tried this as well. Here is my code.
app.js
app.get('/templates/:templateid',indexController.getTemplate);
index controller
var indexController = {
index: function(req, res) {
res.render('index');
},
getTemplate:function(res,req){
res.render('templates/' + req.params.templateid);
}
};
module.exports = indexController;
Here is my main.js
var app = angular.module('myApp',['ui.router']);
app.config(function($stateProvider,$urlProvider){
$stateProvider('home',{
url:'/home',
templateUrl:'templates/home.jade',
controller: 'HomeController'
})
})
app.controller('HomeController',function($scope){
console.log('home is here');
})
My index.jade shows as so
extends layout
block content
h1 Lets Get Cruddy
<div ui-view></div>
I have called ng-app in my layout. This should be fairly simple right?
The router only interprets html
you should point the template url to the compiled html file so
templateUrl:'templates/home.html
that's if templates/home.jade compiles to templates/home.html
As Dr Manhattan said, AngularJS does not render a Jade file, however, if you have a server side language such as NodeJS, you can change view engine to Jade.
For simplicity sake, I would also recommend creating a NodeJS application with Express so you can create a route that will render the view and take advantage of the simplicity of Jade.
Add the following to your App.js file in your NodeJS application:
app.set('view engine', 'jade');
In your NodeJS route, you will add something like this:
var router = express.Router();
// index.js
// http://www.yourdomain.com/ is the path to this route
router.get('/', function(req, res, next) {
res.render('home', {
title: 'Express'
});
});
In your main.js file, you will change the templateURL to the following:
templateUrl:'/',
Jade will render the template to HTML and make it readable for AngularJS.

Resources