Display data in a Vue component with ajax - 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">

Related

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.

Vue.js bind ajax loaded v-on click handlers

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

How to use multiple fineuploader instances with manual upload buttons with one template

With the fine-uploader plugin I am trying to add multiple (dynamic could be 1, or 10) instances with an optional caption field and a manual upload button per section.
The form I am uploading from is dynamically generated in layout as well as content, the uploaded files have to be stored by the handler based upon the section of the form as well as the instance of fine-uploader. I also need the ability to effectively upload each instance of fine-uploader independently
The issue that I am hitting is following the guidelines & demo for the manual upload option, ie adding a click function it will always find only the first instance as it searches for the button using .getElementById.
I can get around this by defining a new template for each instance however I would prefer to use a single template.
The template code (for each instance - abbreviated for simplicity) is
<script type="text/template" id="qq-template-manual-trigger#XX#">
<div class="qq-uploader-selector qq-uploader" qq-drop-area-text="Drop files here">
...
<div class="buttons">
<div class="qq-upload-button-selector qq-upload-button">
<div>Select files</div>
</div>
<button type="button" id="trigger-upload#XX#" class="btn btn-primary">
<i class="icon-upload icon-white"></i> Upload
</button>
</div>
...
<ul class="qq-upload-list-selector qq-upload-list" aria-live="polite" aria-relevant="additions removals">
<li>
...
<input class="caption" tabindex="1" type="text">
...
</li>
</ul>
...
</div>
</script>
<div id="fine-uploader-manual-trigger#XX#"></div>
and the uploader script
<script>
var manualUploader#XX# = new qq.FineUploader({
element: document.getElementById('fine-uploader-manual-trigger#XX#'),
template: 'qq-template-manual-trigger#XX#',
request: {
inputName: "imagegroup[]",
endpoint: '/SaveFile.aspx'
},
autoUpload: false,
debug: true,
callbacks: {
onError: function(id, name, errorReason, xhrOrXdr) {
alert(qq.format("Error on file number {} - {}. Reason: {}", id, name, errorReason));
},
onUpload: function (id) {
var fileContainer = this.getItemByFileId(id)
var captionInput = fileContainer.querySelector('.caption')
var captionText = captionInput.value
this.setParams({
"descr[]": captionText,
<-- Other parameters here -->
}, id)
}
},
});
qq(document.getElementById("trigger-upload#XX#")).attach("click", function () {
manualUploader#XX#.uploadStoredFiles();
});
</script>
in the ideal world I would prefer simply have a single
<script type="text/template" id="qq-template-manual-trigger">
....
</script>
then where required multiple times through the form
<div id="fine-uploader-manual-trigger"></div>
<script>
var manualUploader#XX# = new qq.FineUploader({
element: document.getElementById('fine-uploader-manual-trigger'),
template: 'qq-template-manual-trigger',
...
}
qq(document.getElementById("trigger-upload")).attach("click", function () {
manualUploader#XX#.uploadStoredFiles();
});
</script>
The use of the attach function by calling .getElementById just feels wrong, or at the very least cludgy, is there a better way of activating the upload on a per-instance basis?
Thanks in advance
K
Sorted, but if anyone has a better answer...
Instead of using the demo of document.getElementById("trigger-upload")
Simply use document.querySelector("#fine-uploader-manual-trigger #trigger-upload")
eg
<div id="fine-uploader-manual-triggerXX"></div>
<script>
var manualUploaderXX = new qq.FineUploader({
element: document.getElementById('fine-uploader-manual-triggerXX'),
template: 'qq-template-manual-trigger',
... // omitted for brevity
}
qq(document.querySelector("#fine-uploader-manual-triggerXX #trigger-upload")).attach("click", function () {
manualUploaderXX.uploadStoredFiles();
});
</script>

Can't pass data from blade to vue (Laravel 5.3)

I'm trying to get Vue components working in Laravel 5.3 and I want to pass data from my blade template to a Vue component.
But I'm getting an error and none of the answers I've found so far have worked.
I'm using the example component that comes with the fresh install. In my blade template I have:
<example :testinfo="someinfo"></example>
In my Example.vue I have:
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example Component</div>
<div class="panel-body">
{{testinfo}} I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['testinfo'],
mounted() {
console.log('Component ready.')
}
}
</script>
The Vue component does load, but it does not display the testinfo, and it generates this error message:
Property or method "someinfo" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option. (found in root instance)
referenced to your error ->
Property or method "someinfo" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in root instance)
it means that someinfo model is not declared from your vue parent. it should be wrapped in data { someinfo:null } and from there supply him data and pass it in your component example.
regarding passing with data from vue blade. you should called ajax from your vue method like
Vue new(){
data : { someinfo : null },
ready :function() / mounted() vue2
{
this.getSomeInfo();
}
methods : {
getSomeInfo : function(){
var self = this;
your ajax request here then
self .someinfo = (your ajax.response)
}
}
}
you need an sperate ajax call from controller to achieve to get your information from controller.
after ajax call success then time to put the response to your vue model then it will automatically pass to your components re actively because of two way binding.
The answer from Tony Fale wasn't exactly what I was looking for but it did give me a clue that helped me think of the answer.
In this code:
<example :testinfo="someinfo"></example>
I thought "someinfo" would just be treated as a string but Vue treats it as a JavaScript variable. Since someinfo isn't defined anywhere, it causes an error.
If instead I do:
<example :testinfo="{somekey: 'someinfo'}"></example>
and change Example.vue to:
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example Component</div>
<div class="panel-body">
{{testinfo.somekey}} I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
It works as expected.

vue.js 2.0 load component dynamically in laravel 5.3

Is it possible to load a component dynamically when clicking a list item in vuejs 2.0 and laravel 5.3? I have a standard Laravel app but on one section of the site (shows reports) I want to turn this page into a single page application using vuejs. I load the default report in using a vue component and all works well, like so:
<div class="col-md-3 col-sm-6">
<div class="card-box">
<h2>Reports</h2><br>
<ul>
<li>Daily</li>
<li>Weekly</li>
<li>Season</li>
<li>Label</li>
<li></li>
</ul>
</div>
</div>
<div class="col-md-9 col-sm-6">
<div class="card-box main">
<reports-homepage></reports-homepage>
</div>
</div>
What I'm trying to achieve is when one of the li items is clicked the <reports-homepage></reports-homepage> is changed dynamically according to which li is pressed. So it could become <reports-daily></reports-daily> for example.
I've tried putting a #click on the li component and catching that in a script below in the blade section but that gives me the following error:
[Vue warn]: Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <script>.
As pointed in the official documentation you can use dynamic components. In your case it could look something like this:
HTML
<div id="app">
<div class="col-md-3 col-sm-6">
<div class="card-box">
<h2>Reports</h2><br>
<ul>
<li #click="setComponent('daily')">Daily</li>
<li #click="setComponent('weekly')">Weekly</li>
<li #click="setComponent('season')">Season</li>
<li #click="setComponent('label')">Label</li>
</ul>
</div>
</div>
<div class="col-md-9 col-sm-6">
<div class="card-box main">
<component v-bind:is="currentComponent"></component>
</div>
</div>
</div>
JS
var vm = new Vue({
el: '#app',
data: {
currentComponent: 'daily'
},
components: {
'daily': { /* component object */ },
'weekly': { /* component object */ },
'season': { /* component object */ },
'label': { /* component object */ }
},
methods: {
setComponent: function (component) {
this.currentComponent = component;
}
}
})
And that should do what you are trying to achieve. Let me know if it helped!

Resources