Issue with Vue instance in laravel [duplicate] - laravel

I want to test a simple vue.js in laravel blade system, Here is my code in test.blade.php view file:
<div id="app">
<p>{{message}}</p>
</div>
<script src="{{url('/assets/js/vue/vue.min.js')}}"></script>
<script>
new Vue({
el:'#app',
data:{
message:"hello world"
}
});
</script>
The problem is while rendering view file laravel wants to access the message as a variable or constant and because there is no any message variable passed to view I get Use of undefined constant exception. So what's the solution?

add #{{message}}
that will tell blade to ignore this.

It's not a good approach to combine the same notation for front-end and back-end. Of course, with the #, Blade can ignore.
A much cleaner idea is to extract the front-end from back-end, because Blade and Vue.js use the same notation:
Front-end with html, css en javascript (in your case Vue.js)
Back-end (in php, Laravel in your case) as REST-api with php that returns json
The big advantages:
It's more secure
It's more maintainable
It's cleaner

Related

Integrate Laraval with Vue js

I present to you my problem. I am working on a project in Laravel and I initially integrated Vue js as a script within a blade view like this, importing Vue with CDN.
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
var app = new Vue({
el: '#app',
data: {
search: '',
//other data .........
},
})
All the logic (methods and data) are inside the blade view script and I don't use components for now. In the development of the project I had the need to add a component (Tiny mce - wysiwyg). For this I had to use Laravel Mix, in order to load the component into the view.
require('./bootstrap');
window.Vue = require('vue').default;
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('tinymce', require('./components/Tinymce.vue').default);
const app = new Vue({
el: '#app',
});
First question
The first question I ask myself is: the two instances of Vue, the one inside the source file /resources/js/app.js and the one inside the blade view must have hook to the same HTML element, and therefore have the same ID?
el: '#app',
I cannot move the Vue instance from the blade file into the app / js file because it intertwines with php code. I must necessarily remain two different instances. One is used to load the component, in this case Tiny Mce and the other to run the script within the Laravel blade view. How do these two instances behave and interact?
Second question
Also the second question I ask myself is: do I need to cdn the Vue into the page, including the script
<script src="{{ asset('js/app.js') }}" defer ></script>
Importing Vue inside the app.js file, I am unable to remove the Vie via CDN in the views
the two instances of Vue must have hook to the same HTML element, and therefore have the same ID?
No, on the contrary I don't thinks it's a great idea to assign two different instances to the same element. You could have some weird behaviour in case the two instances start interfering with each other. Use two separate HTML roots for the instances
do I need to cdn the Vue into the page, including the script
No. If in your compiled js you assign the Vue instance to the window object, you don't need the CDN anymore. Just be careful: your compiled js file must be included before your script tag with the blade vue instance, without defer or async.
<script src="{{ mix('js/yourfile.js') }}"></script>
// ^^^ this one before and without defer
// no vue included through CDN
<script>
var app = new Vue({
....
})
</script>
Now, let's address the elephant in the room. Having a whole vue instance in a blade file is a bad practice, in may work up to a certain point but, as you noticed in this case, it becomes a problem.
I cannot move the Vue instance from the blade file into the app / js file because it intertwines with php code.
The only way I can imagine PHP and JS code interacting with each other is in order to pass some data from PHP to JS. In case that's the problem, here is an idea on how to do it:
In your blade file, you attach the data structure you want to share with Js to the window object:
<script>
window.sharedData = {
key: #if($cond) 'value1' #else 'value2'
...
}
</script>
If you have a PHP object that you want to share directly, you can use the #json directive:
<script>
window.sharedData = #json($sharedData);
</script>
Now, AFTER this script tag you can include the mix file:
<script src="{{ mix('js/yourfile.js') }}"></script>
There, you can use the window.sharedData object with the data build using PHP code:
var app = new Vue({
data: window.sharedData
})

Add variable to form action in Laravel Vue Component

How can I add a variable to the form action in Laravel Vue Component?
<form method="POST" action="/thoughtjournal/{{id}}/update">
First, you might want to use Vue models and Axios to submit your form from Vue. It's kind of one of the magical parts of working with Vue.
However, to answer your question you need to bind the action attribute using js, so you need to create a variable in the Vue's data array of id and then use the following:
<form method="POST" :action="'/thoughtjournal/' + id + '/update'">
Again, tough, that is very much not how you should be working in vue. Instead you should use v-model biding to build up/edit the thought journal model, then post or patch it using axios.

How to enhance an existing Laravel project with VueJS?

I just finished my project using only the Laravel framework. Now I want to add vue.js into my project to render the views without loading them. I went through some tutorials and found that I need to convert my blade files into Vue components to achieve this. But as I know it's a big process as some of the functions won't work in VueJS. And I don't know how to do it. Please, someone, guide me here on how to do that. Thanks in advance.
Rebuild your basic structure into a Vue template:
// MyTemplate.vue
<template>
<div> <!-- keep this single "parent" div in your template -->
<!-- your Blade layout here -->
</div>
</template>
<script>
export default {
props: [ 'data' ]
}
</script>
Add your Vue template as a global component in app.js:
// app.js
import Vue from 'vue';
window.Vue = Vue;
Vue.component('my-template', require('./MyTemplate.vue').default);
const app = new Vue({
el: '#app'
});
Use this new Vue template in your Blade template as below:
<my-template :data="{{ $onePhpVarThatHoldsAllYourData }}"></my-template>
Once inside the Vue template, you will not be able to reach back to your Laravel methods (e.g. #auth) or for additional data without an Ajax request, so make sure you package all the data you need in your Vue template up front. All of the data you send in will be prefixed inside the Vue template with the name of the prop you assign it to, in this case data.
Note, once you get more familiar with Vue you will likely start segregating the individual data values being passed to your template. For that, you will need to specify additional props in the props array in step 1, e.g.
props: ['a', 'b', 'c'],
and then individually pass their values with
<my-template :a="{{ $a }}" :b="{{ $b }}" :c="{{ $c }}"></my-template>
Convert your Blade directives to Vue directives:
Loops (e.g. #foreach) to v-fors:
#foreach ($items as $item)
<li>{{ $item }}</li>
#endforeach
becomes
<li v-for="item in data.items">{{ item }}</li>
Control structures (e.g. #if ($something !== $somethingElse) ... #endif) to v-ifs:
<div v-if="data.something !== data.somethingElse">
...
</div>
In general, as it was already mentioned in comments, there's no short way for converting your application from blades to VueJS components. Anyway, if you consider migrating to VueJS, I'd recommend you to make a full migration instead of partially using Vue components.
The main idea of migration to VueJS is to transfer all logic that you did in blade templates (like foreach's, if's etc) to Vue components and fetch all data using AJAX requests (e.g. with help of axios or nativelly).
In this case, your controllers should return all data needed for page rendering and Vue components will take care of rest rendering logic.
Also, it's a good option to use vue-router to handle rounding and make your application behave as SPA. In this case, you should create one wildcard route in your application that will return only one blade template. Inside of this template you should insert root tag that will initiate VueJS. The rest will be on the VueJS side.
If you are planning to migrate the whole application then start with authentication.
Part #1: https://codebriefly.com/laravel-jwt-authentication-vue-ja-spa-part-1/
Part #2 https://codebriefly.com/laravel-jwt-authentication-vue-js-spa-part-2/
This tutorial helped me in the past to getting started. After that split your code into components.
If you want to learn basics first then you can go with this tutorial I found this useful.
https://www.youtube.com/playlist?list=PL4cUxeGkcC9gQcYgjhBoeQH7wiAyZNrYa
Hope this helps!

How to ignore an html element in vuejs

How to prevent Vue.js from running code within the < code > tags produced by markdown? It's a Laravel 5.5 + Vue.js 2.x project with 'andreasindal/laravel-markdown' package for markdown. The code that's Vue is trying to run is actually a Laravel Blade directive and it seems that Blade itself doesn't try to process it (since I'm getting a Vue error regarding this in the console).
{{ session('notificationType') }}
I tired modifying the Parsedown.php class (which is used by 'andreasindal/laravel-markdown') to replace all the '{' with the HTML ASCII characters. The replacement did work, but Vue still processed those.
If you do not want Vuejs to evaluate anything inside an HTML element you can use the v-pre directive as:
<code v-pre> {{ name }} </code>
In the above example vue will ignore everything inside the tags so, the name variable won't be evaluated and everything will be rendered as is.
* more on v-pre

How to add a Vuejs component to a Laravel Spark application?

I am working on a Laravel 5.2 project with Laravel Spark (which still in beta as at time of writing) and trying to add some Vuejs functionality using the default layouts and views.
My first attempt failed because I simply tried to create a new div within the home view and bind my Vue code to that div. Here is the div:
<div id="my-stuff">
<p>#{{ test }}</p>
</div>
And here is the corresponding JS code:
new Vue( {
el: '#my-stuff',
data: {
test: 'This is a test'
}
});
What I expected to see were the words "This is a test" appear within that div on the home screen, but of course nothing appeared because, as mentioned, Vue gets bound to a div immediately after the body tag (well, I'm assuming that's why anyway).
I think the solution to my problem is to use Vue components, which themselves look fairly straightforward, but I have no idea where to put my code, how to integrate my code with the Gulp process, which Spark file I need to modify (if any?) to register my component and how to ensure that my component gets registered before the Vue instance gets created.
Any help would be much appreciated.
Addendum 1
To reproduce the exact same set-up as I'm using, one would need to install a fresh copy of Laravel 5.2, then use the spark installer to add the spark stuff, then add app.js containing the code below to the public folder, add the corresponding div anywhere in the home view and add a script tag to include app.js right below the script tag that imports the main javascript file produced by gulp.
Whilst it is impractical to reproduce that entire setup in a fiddle, I think the following fiddle illustrates the essence of the problem:
https://jsfiddle.net/5oLLte2e/
From memory you have the same limitation in AngularJS. It is completely reasonable to me why this wouldn't work and the solution in Vuejs is most likely to use components, but the challenge in this situation is knowing how to bundle the component and where to save it in order to integrate it with the gulp config, or if that is even necessary.
Vuejs Components
If you want to have more than one vue instance the short answer is: yes, you need components.
<div id="main-app">
<p>{{ mainMessage }}</p>
<my-app>
<p>Some composable content</p>
</my-app>
</div>
And the scripts will have to be loaded components first:
Vue.component('my-app', {
template: '<div>{{myMessage}}<br/><slot></slot></div>',
data: function() {
return {
myMessage: 'This is my message'
}
}
});
new Vue( {
el: '#main-app',
data: {
mainMessage: 'This is the main module'
}
});
The output will be:
This is the main module
This is my message
Some composable content
Here is the fiddle: Components with Vue
Remember that you can always put the template in the page using a unique id or, more idiomatically using something like:
<script type="x/template" id="my-app">
Your template here
{{ your component variables }}
</script>
Laravel Spark Integration
The steps to adding a component within a Sparkified Laravel application are as follows:
(1) Add the placeholder HTML with the custom tag anywhere on the page, even if a surrounding div has already been Vue-ified. The HTML with the custom component might look like this:
<div id="example">
<my-component></my-component>
</div>
(2) Implement the Vue component and save the JavaScript file in resources/assets/js. By way of example, we might save the following code as my-component.js:
var MyComponent = Vue.extend({
data: function() {
return { message: 'This is a test' }
},
template: '{{ message }}'
})
Vue.component('my-component', MyComponent)
new Vue({
el: '#example'
})
(3) Add one require statement (the second line below) to the code in resources/assets/js/app.js so that the file looks like this:
require('laravel-spark/core/bootstrap');
require('./my-component.js'); // This is the key!
new Vue(require('laravel-spark'));
Note that it is super-important to include the leading ./ in front of the filename, otherwise Browserify will assume it is looking for a npm module instead of a raw file and will fail.
(4) Run gulp and once it has finished, refresh the page. Gulp will call Browserify, which processes resources/assets/js/app.js, which now includes our custom JavaScript to be processed and included in the final public/js/app.js file.
If you carry out these steps on a clean Laravel installation that has had the Spark installer treatment (I made my mods to home.blade.php), you should see the sample text appear on the page.

Resources