Vue.js v-for not rendering component - javascript

I have the following issue, for some reason, the v-for will not render at all. Please find the fiddle here https://jsfiddle.net/tadeyemi/k6s4gv85/ I have absolutely no idea why it isn't working. Someone care to shed some light?
<div id="app">
<h1>Finds</h1>
<div>
<input ref="option">
</div>
<button v-if #click="addFind">
New Find
</button>
<p v-for="(option,idx) in options.slice(1)">
<span #click="removeOption(idx+1)">Option{{idx+1}}: {{option}}</span>
</p>
</div>
and the JavaScript as follows:
new Vue({
el: '#app',
data: {
options: [],
count:0
},
methods: {
addFind: function () {
var msg = this.$refs.option.value;
console.log(this.options);
if( msg.trim() != "" ){
this.count++;
var i = this.count;
this.options[i]= this.$refs.option.value.trim();
}
},
removeOption:function(index){
this.options.splice(index,1);
this.count--;
}
}
});

There are some issues with your code, but the most prominent is that you break some reactivity rules explained here: https://v2.vuejs.org/v2/guide/reactivity.html#For-Arrays
Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue When you modify the length of the
array, e.g. vm.items.length = newLength
Basically: this.options.push(msg.trim()); would work, while this.options[i]= this.$refs.option.value.trim(); won't
I edited the fiddle a little to make it work: https://jsfiddle.net/63jyw7gz/

Related

How to replace a string with a component (vue)

I have strings that contains ### and I am replacing with array values. Now I want to use them with a component, I created the component and it works but I don't know how to use it in the strings. I don't want to wrap them manually because I don't know how the strings will be, it can have several ###. If it has 2 ###, options will have 2 subArrays.
What is the better way to do it?
Code: https://jsfiddle.net/tsobh4nu/
Vue.component('opt', {
template: `<label>
<span class="bold" v-for="(str,idx) in options">
{{str + " / "}}
</span>
</label>`,
props:{options: Array}
})
new Vue({
el: '#app',
data: {
str: "I have ### and you have a ###.",
options: [
['AAA', 'BBB', 'CCC'],
['XXX', 'YYY', 'ZZZ']
]
},
computed:{
replacedStr(){
let newStr = this.str;
this.options.forEach(option=>{
newStr = newStr.replace('###',this.concatenateOptions(option));
})
return newStr;
}
},
methods: {
concatenateOptions(strArr) {
let separator = "";
let strOptions = "";
strArr.forEach(word => {
strOptions += separator + word;
separator = " / ";
});
return strOptions;
}
}
})
.bold {
font-weight: bold
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<p>I want something like this, but using components: </p>
{{replacedStr}}
<br>
<hr>
My Components:<br>
<opt :options="options[0]"></opt>
<br>
<opt :options="options[1]"></opt>
</div>
Many thanks.
This is more general, but I hope it will help someone. Add a dynamic component in your template: <component v-bind:is="processedHtml"></component>.
Then add a computed method:
computed: {
processedHtml () {
let html = this.html.replace('[Placeholder]', '<my-component></my-component>');
return {
template: '<div>' + html + '</div>'
}
}
}
Where <my-component> is your custom component and the this.html is your HTML content that contains the placeholder [Placeholder].
It is important to return an element that has one root node. That's why the return is wrapped with <div>.
Read more advanced tutorial about this issue here in my blog. For example, to pass props to <my-component>
I just experienced the same issue. I had an element that needed to display the current count of an item. The current count came from the store and was constantly changing. I used v-text. I know this is pretty situation specific, but hopefully it helps someone down the line.
<P id="results_count" v-text="current_count"></P>
and in the data portion of the component I had a property named current_count that was updated via methods.

Vue.js keyup events and v-model length on Android not working as expected

On Android the length of v-model is returning 0 on keyup unless its a number or the space bar key. Does anyone know why that is and how to make it fire the keyup event no matter what key it is and get the length? Here is a cleaned up version of what I have:
<template>
<div class="typeahead">
<input
v-model="query"
v-on:keyup="suggestTerms"
>
</div>
</template>
<script>
export default {
data () {
return {
query: '',
}
},
methods: {
suggestTerms () {
console.log('query length = ' + this.query.length);
}
}
}
</script>
P.S. This works on every browser and device except Android.
There have been instances when v-model didn't update on mobile in some cases. Issue on Forum (current), Another from Forum
You can also code the v-model explicitly, it works in both android and pc.
function callMe(){
var vm = new Vue({
el : '#root',
data : {query : ''},
methods: {
suggestTerms () {
console.log('query length = ' + this.query.length);
}
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<h3>Decomposed</h3>
<div>
<input type='text' :value='query' #input='evt=>query=evt.target.value' v-on:keyup="suggestTerms">
<b>{{query}}({{query.length}})</b>
</div>
</div>

Vue.js - Trouble displaying results from API call in component

Experimenting with Vue.js, trying to display results from a Wikipedia API call in a component using the v-for directive, but something is not working on the back end and I don't know what it is.
Link to the jsFiddle
HTML
<div id="app">
<input type="text" v-model="searchTerm" v-on:keyup="getResults">
<searchResult
v-for="item in results"
v-bind:result="item"
v-bind:key="item.key"
></searchResult>
</div>
Javascript
new Vue({
el: '#app',
data: {
api: "https://en.wikipedia.org/w/api.php?",
searchTerm: 'Ron',
searchDataString: "action=opensearch&format=json&origin=*&uselang=user&errorformat=html&search="+this.searchTerm+"&namespace=0%7C4&limit=20&profile=fuzzy",
searchCall: this.api+""+this.searchDataString,
results: []
},
methods: {
getResults() {
this.searchCall = this.api+"action=opensearch&format=json&origin=*&uselang=user&errorformat=html&search="+this.searchTerm+"&namespace=0%7C4&limit=20&profile=fuzzy";
//console.log( this.searchCall );
axios.post( this.searchCall )
.then(response => { this.processResults(response.data) });
},
processResults(data) {
//console.log( data );
for(var i = 0; i < data[1].length; i++) {
var resultItem = { key:i, link:data[3][i], name:data[1], description:data[2][i] };
this.results.push(resultItem);
console.log(resultItem);
}
}
}
});
Vue.component( "searchResult", {
props:['result'],
template: "<a target='_blank' href='{{ result.link }}'><div class='search-result'><h3>{{ result.name }}</h3><p>{{ result.description }}</p><div></a>"
});
The two issues on my mind are
the error message that shows in the console when typing input, and
that the array of results is creating empty objects instead of passing the data
When I look at the array in the console, all it shows are getters and setters. I'm new to this, so maybe that's what it's supposed to be doing.
I'm so close to getting this working, but I'm at my wits end, help is much appreciated.
The problem with your code is that html tags aren't case sensitive so naming a component searchResult causes issues. If you need to use searchResult, you'll have to use <search-result> in your template. I find it better just to avoid the problem altogether and give components lower-case names. Here are docs about the issue: https://v2.vuejs.org/v2/guide/components.html#Component-Naming-Conventions
You mentioned "the error message that shows in the console when typing input". I didn't get any errors copying and pasting your code (other than forgetting to include axios). What error are you getting?

Vue.js v-if inside v-for not actively listening to array change

I am trying do display an element for each array inside an array and display that element if its array contains a true boolean. The if function runs the first time but the element does not disappear when the value changes.
<li v-for="(value, index) in list">
<span> {{ value[0] }} </span>
<span v-if='value[1]'> {{ value[2] }} </span>
</li>
var List = new Vue({
el: "#List",
data: {
list: ['fizz',true,0],
},
methods: {
toggleItem: function(index) {
this.list[index][1] = !this.list[index][1];
},
}
})
I should be able to run
List.toggleItem(0)
If you are updating the array in Vue then use Vue.set(); so that Vue can track the changes and update the template
for example,
Vue.set(value, 1, false);
Note: simpley updating like this value[1] = false; this will not work
For more, https://v2.vuejs.org/v2/guide/list.html#Caveats

Why oldIndex and newIndex always return 0 for Sortable JS (rubaxa-sortable)?

I am using sortable js for drag and drop action. (Link to github page) As I am using vue.js as well, I am using this plugin to bridge them. I am new to both of the library and so I am trying to duplicate the example given in the plugin. (i.e. this example)
HTML section:
<div class="drag">
<h2>List 1 v-dragable-for</h2>
<div class="dragArea" >
<template v-dragable-for="element in list1" options='{"group":{ "name":"people", "pull":"clone", "put":false }}' track-by="$index">
<p>{{element.name}}</p>
</template>
</div>
<h2>List 2 v-dragable-for</h2>
<div class="dragArea">
<div v-dragable-for="element in list2" options='{"group":"people"}' track-by="$index">{{element.name}}</div>
</div>
</div>
Javascript part:
var vm = new Vue({
el: "#main",
data: {
list1:[{name:"John" , id:"1"},
{name:"Joao", id:"2"},
{name:"Jean", id:"3"} ],
list2:[{name:"Juan", id:"4"},
{name:"Edgard", id:"5"},
{name:"Johnson", id:"6"} ]
},
methods:{
}
});
It works fine on jsfiddle, but when I try to duplicate the case on my local server, it always return 0 for both oldIndex and newIndex in the onUpdate event. This makes the element always insert at the beginning of the second list. Any clue on what can I miss to cause this problem?

Categories

Resources