Hi I'm trying to change my vue wrapper component dropdown with axios. This is my code.
<html>
<head>
<title>title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</style>
</head>
<body>
<div id="el"></div>
<script type="text/x-template" id="demo-template">
<div>
<p>Selected: {{ input.selected }}</p>
<select2 :options="options" v-model="input.selected">
<option disabled value="0">Select one</option>
</select2>
</div>
</script>
<script type="text/x-template" id="select2-template">
<select>
<slot></slot>
</select>
</script>
<script src="http://themestarz.net/html/craigs/assets/js/jquery-3.3.1.min.js"></script>
<script src="https://unpkg.com/vue#2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
Vue.component('select2', {
props: ['options', 'value'],
template: '#select2-template',
mounted: function () {
var vm = this;
$(this.$el)
// init select2
.select2({data: this.options})
.val(this.value)
.trigger('change')
// emit event on change.
.on('change', function () {
vm.$emit('input', this.value)
})
},
watch: {
value: function (value) {
// update value
$(this.$el)
.val(value)
.trigger('change')
},
options: function (options) {
// update options
$(this.$el).empty().select2({data: options})
}
},
destroyed: function () {
$(this.$el).off().select2('destroy')
}
});
var vm = new Vue({
el: '#el',
template: '#demo-template',
data: {
input: {
selected: "all"
},
options: []
},
created: function () {
this.mymethod();
},
methods: {
mymethod: function () {
var vm = this;
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function (response) {
vm.options = [
{id: 'all', text: 'All'},
{id: 1, text: 'Hello'},
{id: 2, text: 'World'},
{id: 3, text: 'Bye'}
];
vm.input.selected = 2;
})
.catch(function (error) {
console.log(error);
});
}
}
});
</script>
</body>
</html>
The problem I have is when I try to add selected item it's not working inside axios. And it's working properly outside axios.
vm.input.selected = 2;
I got selected the all initially as the image shows. Think ajax call does not matter so I reduced the code complexity a bit. Thanks.
You need to recreate the input object inside the axios:
vm.input = { selected: 2 };
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function (response) {
vm.options = [
{id: 'all', text: 'All'},
{id: 1, text: 'Hello'},
{id: 2, text: 'World'},
{id: 3, text: 'Bye'}
];
// recreate the 'input' object for reactivity
vm.input = { selected: 2 };
})
.catch(function (error) {
console.log(error);
});
You've encountered change detection caveat.
Use Vue.set(vm.input, 'selected', value) (or vm.$set) to update properties of your objects.
seems like I had issues with with wrapper component. After I changed the order of options and value in the component's watch this was fixed. I'm adding this in case anyone in the future faced the same issue.
watch: {
options: function(options) {
// update options
$(this.$el).empty().select2({
data: options
})
},
value: function(value) {
// update value
$(this.$el)
.val(value)
.trigger('change')
}
},
Related
With Vue, I get json values from a remote page and I can print it to the page.
But I have to transfer these values to another javascript library. How can I do that?
Data in the page v-for="dta in dataTable" or {{dataTable.height}} etc. I can use it the way. But it is not possible to use the "var graph like = {{dataTable.height}}" in another javascript, how can I do it?
I think I will have to give a work order one at a time. Because first the vue get remote data and then the other javascript should work because the values will come from vue.
index.html
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="vue.min.js"></script>
<script src="apex/apexcharts.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
<style>
textarea {position: fixed;right: 0;top: 0;width: 300px;height: 400px;}
#testGraph1 {width:400px;position: fixed;top:0;right:0;margin-right:500px;}
</style>
</head>
<body>
<div id="app">
<form id="urlParameterForm">
<input type="date" name="startDate" id="startDate" />
<input type="date" name="endDate" id="endDate" />
<input
type="number"
name="pageNumber"
id="pageNumber"
value="1"
v-on:input="changePage"
/>
<input
type="button"
value="Filter"
id="Filter"
v-on:click="changeFilter"
/>
<p>Page : {{ pageActive }}</p>
</form>
<h3>{{title}}</h3>
<div v-for="dta in dataTable">
Height: {{dta.height}}, Type: {{dta.type}}
<h3>Categories</h3>
<ul v-for="dta2 in dta.graphData">
<li>{{dta2.categorie}}</li>
</ul>
<h3>Series</h3>
<ul v-for="dta2 in dta.graphData">
<li>{{dta2.serie}}</li>
</ul>
</div>
<div id='testGraph1'></div>
<textarea>
{{dataTable}}
</textarea>
</div>
<script src="getData.js"></script>
</body>
</html>
getData.js
const app = new Vue({
el: "#app",
devtools: true,
data: {
dataTable: [],
pageNumber: 1,
pageActive :0,
title:'Graph-1'
},
computed: {
url() {
return './dataSql.asp?pg=' + this.pageNumber
}
},
methods: {
changePage: function (event) {
console.log('Change Page',this.pageNumber);
this.pageNumber = event.target.value;
this.init();
},
changeFilter: function (event) {
console.log('Change Filter');
this.init();
},
init() {
let that = this;
console.log('init call');
$.ajax({
type: "POST",
url: that.url,
data:{
startDate:$('#startDate').val(),
endDate:$('#endDate').val(),
pageNumber:$('#pageNumber').val()
},
success: function (data) {
console.log('data remote call');
console.log(data.sqlData);
that.dataTable = data.sqlData;
}
});
}
},
mounted() {
this.init()
}
})
var barBasicChart = {
chart: {
height: 350, /*dta.height !Problem...*/
type: 'bar', /*dta.bar !Problem...*/
},
plotOptions: {
bar: {
horizontal: true,
}
},
dataLabels: {
enabled: false
},
series: [{
data: [10,5,3] /*dta.graphData.serie !Problem...*/
}],
xaxis: {
categories: ['Test-1','Test-2','Test-3'], /*dta.graphData.categorie !Problem...*/
},
fill: {
colors: '#ffcc33'
}
}
var bar_basic_chart = new ApexCharts(
document.querySelector("#testGraph1"),
barBasicChart
);
bar_basic_chart.render();
dataSql.asp
{"sqlData":[{"height":350,"type":"bar","graphData":[{"categorie":"Bursa","serie":4},{"categorie":"Tekirdağ","serie":3}]}]}
Question Update (2021-04-12)
As "var app = new Vue ({...})", I assigned the vue code to a variable called app.
I can reach "data: {title}" by typing app._data.title.
But interestingly, I cannot access json by typing "data: {....dataTable: []....}".
"var vueDatas = [];vueDatas = app._data.dataTable; "
As a follow up to my comment, I am posting components from a sample Chart.js project that I built recently. It demonstrates the idea that I was describing in my comment. It was written in Vue.js 2 using the Vue CLI.
chart-configurations.js
const samplePieConfig = {
type: 'pie',
data: {
datasets: [{
data: [],
backgroundColor: [
'rgba(255, 0, 0, 0.8)',
'rgba(0, 255, 0, 0.8)',
'rgba(0, 0, 255, 0.8)',
]
}],
// These labels appear in the legend and in the tooltips when hovering different arcs
labels: [
'Red',
'Green',
'Blue'
]
},
options: {
responsive: false
}
}
export {
samplePieConfig
}
ChartTest.vue
<template>
<div class="chart-test">
<h3>Chart Test</h3>
<canvas id="chart-canvas" width="500" height="500" ref="chartref"></canvas>
</div>
</template>
<script>
import Chart from 'chart.js';
import { samplePieConfig } from '#/chart-configurations.js'
export default {
data() {
return {
chartObj: null,
chartConfig: samplePieConfig
}
},
props: {
chartData: {
type: Array,
required: true
}
},
methods: {
setChartData() {
this.chartConfig.data.datasets[0].data = this.chartData;
}
},
mounted() {
this.setChartData();
this.chartObj = new Chart(this.$refs.chartref, this.chartConfig);
},
// beforeDestroy() {
// // This necessary if canvas is reused for a new chart
// this.chartObj.destroy();
// }
}
</script>
App.vue
<template>
<div id="app">
<chart-test v-if="dataReady" :chartData="pieChartData" />
</div>
</template>
<script>
import ChartTest from '#/components/ChartTest'
export default {
name: 'App',
components: {
ChartTest
},
data() {
return {
barChartData: [12, 19, 3, 5, 2, 3],
pieChartData: [10, 20, 30],
dataReady: true
}
},
methods: {
getData() {
this.dataReady = true;
}
},
mounted() {
// Simulate API call
setTimeout(this.getData(), 2000);
}
}
</script>
since you have an asynchronous request, so you can not access dataTable until it fetched
change your ajax request like this:
$.ajax({
type: "POST",
url: that.url,
data:{
startDate:$('#startDate').val(),
endDate:$('#endDate').val(),
pageNumber:$('#pageNumber').val()
},
success: function (data) {
console.log('data remote call');
console.log(data.sqlData);
that.dataTable = data.sqlData;
that.$emit('data-fetched'); // fire an event when data was ready to use
}
});
and outside your Vue instance you can listen that event like this:
app.$on('data-fetched', function(){
console.log(app.$data.dataTable)
});
and it's should work
I use the jquery easy autocomplete plugin which has an internal event "onSelectItemEvent".
now i want to call this event from outside (since it is bound to an extensive function i wrote already).
I prepared a fiddle, but triggering the plugins event with this doesn't work :)
$("#example-ac").easyAutocomplete(this.list.onSelectItemEvent());
$(document).ready(function() {
var options_ac = {
url: "https://fcgi.msk.link/model-json.pl?site=test",
getValue: function(element) {
//console.log(element);
return element;
},
list: {
match: {
enabled: true
},
sort: {
enabled: true
},
maxNumberOfElements: 8,
onSelectItemEvent: function() {
$("output").html($("#example-ac").val())
}
},
theme: "square"
};
$("#example-ac").easyAutocomplete(options_ac);
$("#trigga").click(function() {
$("#example-ac").easyAutocomplete(this.list.onSelectItemEvent());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/easy-autocomplete/1.3.5/easy-autocomplete.themes.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/easy-autocomplete/1.3.5/easy-autocomplete.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/easy-autocomplete/1.3.5/jquery.easy-autocomplete.min.js"></script>
<input id="example-ac" />
<br>
<input id="example-ac" /><br/>
<output></output>
<button id="trigga">
trigger
</button>
http://jsfiddle.net/Lgetus29/
Thanks for a hint if this works or if the solution has to be done another way. the codepen example is just small code while the real coding for this internal function is massive, so i want to reuse. maybe i better create a function outside the plugin then reuse this function in the "onSelectItemEvent()", is that even possible?
THANKS !!
Why not use it like
$("#trigga").click(function() {
options_ac.list.onSelectItemEvent()
});
So your final code will look like
$(document).ready(function() {
var options_ac = {
url: "https://fcgi.msk.link/model-json.pl?site=test",
getValue: function(element) {
//console.log(element);
return element;
},
list: {
match: {
enabled: true
},
sort: {
enabled: true
},
maxNumberOfElements: 8,
onSelectItemEvent: function() {
$("output").html($("#example-ac").val())
}
},
theme: "square"
};
$("#example-ac").easyAutocomplete(options_ac);
$("#trigga").click(function() {
options_ac.list.onSelectItemEvent();
});
});
I'm using jquery select2 Wrapper Component. This is my code,
<select2 :options="brands_options" #change="onChange" v-model="brand">
<option disabled value="0">Select one</option>
</select2>
<select2 :options="models_options" v-model="model">
<option disabled value="0">Select one</option>
</select2>
<script type="text/x-template" id="select2-template">
<select>
<slot></slot>
</select>
</script>
<script type="text/javascript">
Vue.component('select2', {
props: ['options', 'value'],
template: '#select2-template',
mounted: function () {
var vm = this
$(this.$el)
// init select2
.select2({data: this.options})
.val(this.value)
.trigger('change')
// emit event on change.
.on('change', function () {
vm.$emit('input', this.value);
});
},
watch: {
value: function (value) {
// update value
$(this.$el)
.val(value)
.trigger('change')
},
options: function (options) {
// update options
$(this.$el).empty().select2({data: options});
}
},
destroyed: function () {
$(this.$el).off().select2('destroy');
}
});
var vm = new Vue({
el: '#el',
delimiters: ["[[", "]]"],
data: {
brand: 0,
model: 0,
brands_options: [],
models_options: [],
cross_border: true,
},
created: function () {
this.loadBrands();
},
methods: {
loadBrands: function () {
var vm = this;
axios.get('http://localhost:81/tenly/public/get_brands')
.then(function (response) {
vm.brands_options = response.data;
{# alert(JSON.stringify(vm.brands_options[0].id));#}
axios.get('http://localhost:81/tenly/public/get_brand_model/' + vm.brands_options[0].id)
.then(function (response) {
vm.models_options = response.data;
{# alert(JSON.stringify(vm.models_options));#}
})
.catch(function (error) {
vm.models_options = 'An error occured' + error;
});
})
.catch(function (error) {
vm.brands_options = 'An error occured' + error;
});
},
onChange(event) {
alert(event.target.value);
}
}
});
</script>
Here I'm trying to alert value from onchange event. think #change="onChange" I added is wrong but not sure how to add correctly. It would be great if someone can help achieve it.
Since you're emitting an event from child component select2 via this statement :
vm.$emit('input', this.value);
so you should do something like :
<select2 :options="brands_options" #input="onChange" v-model="brand">
<option disabled value="0">Select one</option>
</select2>
and add onChange to the methods of the Vue instance as follows :
methods: {
onChange(value){
//do whatever you want with value
},
loadBrands: function () {
....
I'm trying to extend the select2 example to be more practically useful. So far I've added multiselect functionality, and trying to allow custom select2 configuration.
https://jsfiddle.net/5ytm3LL6/
It appears that function properties of props objects are being stripped when handed to component.
What is a solution for a parent to give widget component configuration with js functions?
I'm somewhat confused, because the embedded version actually shows params being transferred properly in the built-in console output, while jsfiddle browser console output does not. However, both versions do not pass the functions to select2 widget.
Vue.component('select2', {
props: ['options', 'value', 'params'],
template: '<select><slot></slot></select>',
mounted: function () {
var vm = this, params = $.extend({}, this.params || {});
console.log(this.params, params);
params.data = this.options;
$(this.$el).val(this.value).select2(params).on('change', function () {
vm.$emit('input', $(vm.$el).val());
});
},
watch: {
value: function (value) {
var $el = $(this.$el);
if (!_.isEqual($el.val(), value)) {
$el.select2('val', value);
}
},
options: function (options) {
$(this.$el).select2({ data: options });
}
},
destroyed: function () { $(this.$el).off().select2('destroy'); }
});
new Vue({
el:'#app',
data: function () {
return {
value: 'a',
options: [{id:'a', label:'A'}, {id:'b', label:'B'}],
params: {
test: 'TEST',
formatSelection: function (item) {return item.label;},
formatResult: function (item) {return item.label;}
}
};
}
});
<link rel="stylesheet" type="text/css" href="https://unpkg.com/select2/dist/css/select2.css"></style>
<script src="https://unpkg.com/lodash"></script>
<script src="https://unpkg.com/jquery"></script>
<script src="https://unpkg.com/select2"></script>
<script src="https://unpkg.com/vue"></script>
<div id="app">
<select2 v-model="value" :options="options" :params="params"></select2>
</div>
I see js functions you have passed being printed in console log. I have updated your fiddle and put following logs in select2 compoent:
console.log(params.formatResult);
console.log(params.formatSelection);
Which prints following:
function (item) {return item.label;}
function (item) {return item.label;}
I am trying to replicate the TODO MVC in VueJs.
(Please checkout this codepen : http://codepen.io/sankalpsingha/pen/gwymJg )
I have created a component called 'todo-list' with the following code :
Vue.component('todo-list',{
template: '#todo-list',
props: ['todo'],
data: function() {
return {
// Let us set up a isEditing Boolean so that we can know if the user
// will edit something and we need to change the state to reflect it.
isEditing: false,
}
},
methods: {
enableEditing: function() {
this.isEditing = true;
},
editTodo: function(todo) {
// todo.todo = todo.todo.trim();
this.isEditing = false;
},
removeTodo: function(todo) {
//this.todos.$remove(todo); // --> This part is not working?
}
}
});
However, I have the data defined in the app instance :
var app = new Vue({
el: '#todo-section',
data: {
newTodo: '',
todos: [
{
id: 1,
todo: 'Go to the grocery',
completed: false,
},
{
id: 2,
todo: 'See the movie',
completed: true,
},
{
id: 3,
todo: 'Jack Reacher : Tom Cruise',
completed: false,
}
]
},
methods: {
addTodo: function() {
// This will not allow any empty items to be added.
if(this.newTodo.trim() == '') {
return;
}
this.todos.push({
todo: this.newTodo.trim(),
completed: false,
});
this.newTodo = '';
}
}
});
I am not able to delete a single Todo from the list. My guess is that I have to send a emit message to the app instance and put up a listener there to delete the data from it? How do I delete the data?
When I tried to delete by clicking the x button in your codePen example, I see the error: this.$parent.todos.$remove is not a function.
I have not looked deeply into your code. But attempting to access parent component methods using this.$parent is not a good idea. Reason: a component can be used anywhere, and assuming that it will have a $parent with a particular property or method is risky.
As you suggested in your question, you need to use $emit from the child component to delete the data.
There was another similar question here few days ago, for which I created a jsFiddle: https://jsfiddle.net/mani04/4kyzkgLu/
The child component has some code like:
<button #click="$emit('delete-row')">Delete</button>
This sends out an event to parent component. Parent component can subscribe to that event using v-on as seen in that jsFiddle example.
Here is that other question for reference: Delete a Vue child component
It's preferable to use your methods (DeleteTodo, EditTodo...) in your parent.
var app = new Vue({
el: '#app',
data: {
newTodo: '',
todos: [{
id: 1,
title: 'Go to the grocery',
completed: false
}, {
id: 2,
title: 'See the movie',
completed: true
}, {
id: 3,
title: 'Jack Reacher : Tom Cruise',
completed: false
}]
},
methods: {
addTodo: function() {
this.todos.push({
todo: this.newTodo.trim(),
completed: false
});
this.newTodo = ''
},
deleteTodo: function(todo) {
this.todos = this.todos.filter(function(i) {
return i !== todo
})
}
}
});
<div id="app">
<ul>
<li v-for="todo in todos">{{ todo.title }}
<button #click.prevent="deleteTodo(todo)">
Delete
</button>
</li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>