Vue.js bind ajax loaded v-on click handlers - ajax

I'm taking over a project that has a lot of AJAX loaded HTML snippets. I want to progressively introduce Vue.js where I can. I'm not trying to async load any component definitions or javascript, but I would like to load an HTML snippet that has a v-on:click binding like this:
<button class="btn btn-primary" v-on:click="showModal=true">
Show Modal Dialog
</button>
Is there anyway for vuejs to parse html snippets that come down from jQuery and read the v-* attributes?

You can use <v-runtime-template> to load Vue template strings at runtime:
<template>
<div id="app">
<template v-if="template">
<v-runtime-template :template="template"></v-runtime-template>
</template>
<div v-else>Loading...</div>
</div>
</template>
<script>
export default {
data() {
return {
template: ''
}
},
mounted() {
this.template = this.getVueTemplateFromServer();
},
methods: {
getVueTemplateFromServer() { /*...*/ }
}
}
</script>
demo

Related

Using Vue in Laravel Spark - "method not defined on the instance" using vue2-touch-events - what could I do differently?

I am trying to build a very simple, tinder-like swiping application using Laravel Spark and vue2-touch-events. I assume I am doing something extraordinarily dumb, so I appreciate your insight.
I get this warning in my Vue inspector:
[Vue warn]: Property or method "swipeHandler" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
Here is my simple version of all of the relevant code. I changed the v-touch:swipe to just longtap for testing.
/resources/js/app.js:
require('spark-bootstrap');
require('./components/bootstrap');
require('vue2-touch-events');
Vue.component('swipeHandler', './components/swipehandler.vue');
var app = new Vue({
mixins: [require('spark')],
components: {
vue2touchevents,
swipeHandler
},
});
swipe.blade.php:
#extends('spark::layouts.app')
#section('content')
<home :user="user" inline-template>
<div class="container">
<div class="row justify-content-center flex-column-reverse flex-md-row">
<div class="col-md-8">
<div class="card text-center">
<div class="card-header">
<div><i v-touch:longtap="swipeHandler">Swipe Here</i></div>
</div>
</div>
</div>
</div>
</div>
</home>
#endsection
/resources/js/components/swipehandler.vue:
<script>
export default {
methods: {
swipeHandler () {
alert("yay!");
console.log("yay!");
}
}
}
</script>
My Best guess is that you may want to try and add a template to your /resources/js/components/swipehandler.vue component:
<template>
<div>Yay</div>
</template>
<script>
export default {
methods: {
swipeHandler () {
alert("yay!");
console.log("yay!");
}
}
}
</script>
I'm not too familiar with how vue2-touch-events works, so I would need to understand that a bit more to give you a better answer.
Best of luck.

Laravel 6 How to pass parameter to Vue Js #click method

I want to pass a parameter to Vue component. please help
Blade
#extends("./layouts.app")
#section("title")
{{$shop->shop_name}}
#endsection
#section("content")
<addToCart></addToCart>
#endsection
Vue Js
<template>
<div class="button-container">
<button #click="addToCart(product_id)">Add To Cart</button>
</div>
</template>
In your Vue Js
add new prop array
<template>
<div class="button-container">
<button #click="addToCart(product_id)">Add To Cart</button>
</div>
</template>
<script>
export default {
props: ["product_id"],
methods: {
addToCart(product_id)
{
//code
}
}
</script>
in your Blade add :product_id ="product id", in addToCart component.
#extends("./layouts.app")
#section("title")
{{$shop->shop_name}}
#endsection
#section("content")
<addToCart :product_id="***product id goes here***"></addToCart>
#endsection
You should follow these steps to access product_id
inside your addToCart component add product_id like this:
#section("content")
<addToCart :product_id="$product_id"></addToCart>
#endsection
in your component you should get the :product_id with props array like below :
<template>
<div class="button-container">
<button #click="addToCart(product_id)">Add To Cart</button>
</div>
</template>
<script>
export default {
props: ["product_id"],
methods: {
addToCart(product_id) {
//code
}
}
</script>
Note: I suppose that you have the product_id and you do the other part of component correct.

Laravel local vue component registration

I know I can register global components in the file located in resources/js/app.js.
I know when I do this I can use these component in any place (because they are global).
But I don't want that. I have a big application and different functionalities solved in different routes. So I don't want the whole components available in all my views.
How can I register locally the components I want to be available only in one view?
Thanks
Vue js register component in local:
step-1 ) storing the component object in a variable:
var demo = {
data: function() {
return {
message: 'This is a local components.'
};
},
template: `
<div>
<h1>Component: {{ message }}</h1>
</div>
`
};
Step-2 ) Add a component property with the components that we want to register locally.
new Vue({
el: '#app1',
components: { /*Here we have added property*/
'demo': demo
}
});
Step-3 ) Template
<div id="app1">
<demo></demo>
</div>
*Notice: This property should be an object and contain key-value pairs of tag names and configuration objects.
You can do it by importing the component in your parent vue component
<template>
<div>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from '#/folder/ChildComponent'
export default {
components: {
ChildComponent
},
}
</script>
Here is the approach that I follow.
Create a new file in your components folder in resources/js/components/YourComponent.vue
<template>
<div>
<h2>My awesome component</h2>
</div>
</template>
<script>
export default {
}
</script>
And in the view where you want the component, you can import it like below
<template>
<div>
<h2>Import another component</h2>
<awesome-component></awesome-component>
</div>
</template>
<script>
import awesomeComponent from "./components/YourComponent.vue";
export default {
components: {
'awesome-component': awesomeComponent
}
}
</script>

How to use a Laravel Nova Component in a Custom Nova Tool

I'd like to use the same loader as Laravel Nova uses when it's components are loading. I can't get it to compile. It never recognizes where to load the LoadingCard component from. Any help would be appreciated.
<template>
<div>
<heading class="mb-6">Tax Calculator</heading>
<loading-card :loading="loading" class="card relative overflow-hidden w-1/3">
<div v-if="countries.length">
<!--Make form-->
</div>
</loading-card>
</div>
</template>
<script>
import LoadingCard from 'laravel-nova'
export default {
mounted() {
let vue = this;
Nova.request().get('/nova-vendor/tax-calculator/mount')
.then(response => {
vue.countries = response.data.countries;
vue.states = response.data.states;
});
},
}
</script>
<style>
/* Scoped Styles */
</style>
Figured it out. Apparently all the Nova built-in components are available globally. Didn't realize this. All I needed to do to get it to compile was remove the import statement. I modified the code as follows:
<template>
<div>
<heading class="mb-6">Tax Calculator</heading>
<loading-card :loading="loading" class="card relative overflow-hidden w-1/3">
<!--Make form-->
</loading-card>
</div>
</template>
<script>
export default {
mounted() {
let vue = this;
Nova.request().get('/nova-vendor/tax-calculator/mount')
.then(response => {
vue.countries = response.data.countries;
vue.states = response.data.states;
});
},
}
</script>
<style>
/* Scoped Styles */
</style>
For those looking for the list of all the global laravel nova vue components, you can find here:
nova/resources/js/components.js

Display data in a Vue component with ajax

I seem to be misunderstanding how to pass data to a Vue.js component with an ajax call.
My understanding of how this should work:
I need to create an empty object called campaigns in the data section of my component.
Then call method "fetchCampaigns" on page ready to replace the data object.
fetchCampaign method completes an AJAX call and inside of the success callback use this.$set('campaigns', campaigns) to replace the empty campaign object with the newly returned campaign object
Use v-for on the template to iterate through the campaign object and access values with #{{campaign.type}}
My html (I am use vue router, vue resource and laravel blade) :
<router-view></router-view>
<template id="campaignBlock" v-for="campaign in campaigns">
<div class="row">
<div class="block">
<div class="block-title">
<h2>Type: <em>#{{campaign.id}}</em></h2>
</div>
<div class="row"><!-- Grid Content -->
<div class="hidden-sm hidden-xs col-md-4 col-lg-4">
<h2 class="sub-header">#{{campaign.title}}</h2>
</div>
</div>
</div><!-- END Grid Content -->
</template>
Vue component
Vue.component('app-page', {
template: '#campaignBlock',
data: function() {
return{
campaigns: []
}
},
ready: function () {
this.fetchCampaigns();
},
methods: {
fetchCampaigns: function () {
var campaigns = [];
this.$http.get('/retention/getCampaigns')
.success(function (campaigns) {
this.$set('campaigns', campaigns);
})
.error(function (err) {
campaigns.log(err);
});
},
}
})
This is the result of my ajax call from console:
{"campaigns":[{"id":1,"user_id":2,"target_id":1,"name":"Test Campaign","description":"This is a test Campaign","target":"Onboarding","created_at":"-0001-11-30 00:00:00","updated_at":"-0001-11-30 00:00:00","deleted_at":null}]}
I'm not sure why I can't get my vue component to recognize the new data. Anyone see what I'm missing? TIA
Turns out that v-for="campaign in campaigns" should not go on the template tag, but inside of it.
So this:
<template id="campaignBlock" v-for="campaign in campaigns">
<div class="row">
Should be changed to this:
<template id="campaignBlock">
<div class="row" v-for="campaign in campaigns">

Resources