Fail to access DOM element in Vue component when using generic javascript - javascript

I am trying to dynamic to update data from Vue.compnent by using jQuery way on Webpack project. following is code snippet.
<template>
<div id="container">
<slot>show string!!</slot>
<div id="s_container"></div>
</div>
</template>
<script>
export default {
}
const items = [
'thingie',
'anotehr thingie',
'lots of stuff',
'yadda yadda'
]
function listOfStuff () {
let full_list = ''
for (let i = 0; i < items.length; i++) {
full_list = full_list + '<li>{{items[i]}}</li>'
}
// const contain = document.querySelector('#s_container')
const contain = this.$el.querySelector('#s_container')
if (contain != null) {
contain.innerHTML = '<ul ${full_list} </ul>'
} else {
console.log('contain is null');
}
}
listOfStuff()
</script>
but this contain variable is always fail to get #s_container element. How can I get it correctly from outside java script?
Thanks.

First you need to bind your items array into a data return function like this:
export default {
data()
return {
items: ['thingie', 'yadda yadda']
}
}
Then you can use a v-for loop the display this array into a HTML li.
Like this into your template:
<template>
<div>
<ul>
<li v-for="(item, index) in items" :key=index>
{{ item }}
</li>
</ul>
</div>
</template>
In this way you can render a simple list using vue.js, if you need more informations about this feature read this part of the documentation: https://v2.vuejs.org/v2/guide/list.html
Have a good day !

Related

Loop not printing correct results on view

I'm trying make my Coordinates, Dispatcher and Captured At printout the correct totals that correspond to it's ID. Unfortunately, it's only assigning the first ID's totals in its HTML element. Having a bit of a braindead moment trying to fix this.
I know I'm missing something to identify the individual html instance, but I can't figure out how to make that happen.
HTML -
<div v-if="zoomLevel > 10" class="search-data">
<div><strong>Dispatcher:</strong> <span id="dispatcher">{{ dispatcher}}</span></div>
<div><strong>Lng/Lat:</strong> <span id="coordinates">{{ coordinates }}</span></div>
<div><strong>Captured At:</strong> <span id="capturedAt">{{ capturedAt }}</span></div>
</div>
JS -
export default {
data() {
return {
coordinates: '',
dispatcher: '',
capturedAt: '',
}
},
}
Method -
let totalTargets = Object.keys(e.source.data.features).length;
for (let i = 0; i < totalTargets; i++) {
console.log(e)
this.coordinates = e.source.data.features[i].geometry.coordinates.toString().replace("[", "").replace("]"," ").replace(",", ", ");
this.dispatcher = e.source.data.features[i].properties.name;
this.capturedAt = e.source.data.features[i].properties.capturedAt;
}
Console.log printout of method results
You need to iterate on the HTML, with v-for, create a reactive property to your list and can use like this:
<div v-if="zoomLevel > 10" class="search-data" v-for="(feature, index) in features" :key="index">
<div><strong>Dispatcher:</strong> <span id="dispatcher">{{ feature.dispatcher}}</span></div>
<div><strong>Lng/Lat:</strong> <span id="coordinates">{{ feature.coordinates }}</span></div>
<div><strong>Captured At:</strong> <span id="capturedAt">{{ feature.capturedAt }}</span></div>
</div>

fire function one time when element is created (pass to methods) / VueJS

I'm working with BootstrapVue. First I want to explain my code shortly:
I have a v-for with inputs, these I can create as often as I want with a b-button -> addElement. Or I can select an item from my b-dropdown - there I am checking the length of my selected and push the amount of my arrayLength as my inputs.
-> e.g. selected array = ['1111', '2222', '3333'] -> arrayLength = 3 -> 3 inputs
Now I need to get a function fired automatically (marked as ???) when exactly this case happend that I'm selecting something from my dropdown - e.g. is my arrayLength = 3, it should be fired 3 times with correct id, indexParent and indexChild. How can I solve that?
I need this above named parameters in my methods..
Thanks in advance!
<div v-for="(id, indexChild) in inputs" :key="indexChild">
<b-dropdown text="Select" right variant="success">
<b-dropdown-item v-for="(item, indexDropdown) in json" :key="indexDropdown" #click="trySomething(item.Number)">{{item.Name}}</b-dropdown-item>
</b-dropdown>
<b-button v-b-toggle="'newElement'+indexParent+indexChild">Element {{indexChild + 1}}></b-button>
<b-collapse :id="'newElement'+indexParent+indexChild"
<div ???="getValues(id, indexParent, indexChild)"> <!-- how can I fire this when created? -->
<!-- Do some more code -->
</div>
</b-collapse>
</div>
<!-- create new "item"-elements -->
<div>
<b-button #click="addElement()">Add element</b-button>
</div>
methods: {
addProduct() {
this.inputs.push({})
},
trySomething(itemValue) {
var array = [];
const products = this.otherJSON.find((i) => i.Number === itemValue);
for (let key in products.ID) {
array.push(products.ID[key]);
}
this.getLengthArray = array.length;
this.inputs.splice(0) //at first I need to delete all to push exact inputs based on arrayLength
for (let i = 0; i < this.getLengthArray; i++) {
this.inputs.push({});
}
},
getValues(id, indexParent, indexChild) { //Here I need the parameters id, indexParent, indexChild
}
},
data() {
return {
inputs: [{}],
}
},
props: ["indexParent"]
I've just used:
<div v-if="getValues(id, indexParent, indexChild)" v-once></div>
and it worked out for me!

How can i hard code my data from realtime database?

So i have some data stored in a realtime datastore and only the admin can access the page where all the data is displayed, but how do i hard code the data to the website this is what i have and tried:
<!-- my html -->
<div v-for="(option, i) in reserveringen" :key="i">
{{ reserveringen[i] }}
</div>
data: function(){
return {
lidnummer: '',
reserveringen: []
}
},
mounted() {
self = this
const reserveringsref = firebase.database().ref('Reserveringen/')
reserveringsref.once('value', function(snapshot){
const lidnummer = ''
const reserveringen = []
snapshot.forEach(function(childSnapshot){
const data = childSnapshot.val()
self.lidnummer = data.Lidnummer
reserveringen.push(
"<tr><td>" + data.Lidnummer + "</td></tr>"
)
});
self.reserveringen = reserveringen;
});
},
This will only display the array i made as text. Can anyone help me with this issue or am i completely doing this wrong any advice will be thanked!
Your isue is not with RT-db but with Vue i guess;
If you want to build HTML in the JS section (as you do by pushing html tags inside an array), you should use the v-html directive instead of the interpolation.
Something like that
<div v-for="(option, i) in reserveringen" :key="i" v-html="reserveringen[i]">
</div>

Feed Outside JS object into Vue.js component

In my JS I have list of products.
var productData = [{
title: 'Bike',
price: 300
},{
title: 'Guitar',
price: 199
}]
This data is gathered from remote Json in a Async call. So I have to do this in JS.
Eventually, I come to a situation, that I need to display this product. But here are 2 things.
1) In HTML I am outside of my main Vue instance scope. It is so because there is 3rd party API that interacts with those products, apart other things... So This array is not bound to Vue instance in any way.
2) This product list is dynamically created, on the fly. In order to display it, I have to do a good old html string concatenation and then apply it.
Main problem:
Now whenever I need to display a product - I have a Vue.js Component for it. That has a template, and all data goes really nicely. I obviously want to reuse this same template.
So right now I have something like this:
//Vue.js Component, that I want to use, and feed my product to:
Vue.component('product', {
props: ['product'],
template: `
<div class="prod">
<h3>{{product.title}}</h3>
<p>{{product.price}} €</p>
</div>
`, data() {
return {
}
}
});
Next in JS, I have this code:
var prodList = getProductsAsync("3rd party service URL and parameters");
var prodHtml = '';
for(var i = 0; i < prodList.length; i++){
prodHtml += `
<div class="prod">
<h3>${prodList[i].title}</h3>
<p>${prodList[i].price} €</p>
</div>
`;
}
Here I have 2 templates (one as JS html, and another in Vue.js component), that is redundant.
I need to have 1 way to maintain this template. At the moment template is simple, but more functionality will shortly come.
Idealy I would like my JS object to use my Vue.js template. As a result it would also behave as Vue.js component too.
So in my JS I would like to have it like this (But this obviously does not work):
var prodList = getProductsAsync("3rd party service URL and parameters");
var prodHtml = '';
for(var i = 0; i < prodList.length; i++){
prodHtml += ` <product :product='prodList[i]'></product>`; // attempt to use Vue.js component 'on the fly' but this does not work!
}
Any suggestions?
It doesn't work, because there is some order in which you have to create component, html, and Vue instance.
// just use all your code together
// first, prepare the component
Vue.component('product', {
props: ['product'],
template: `
<div class="prod">
<h3>{{product.title}}</h3>
<p>{{product.price}} €</p>
</div>
`
})
// and get products
var prodList = getProductsAsync('/someMountpoint')
// then generate html with unknown tags "product"
var prodHtml = '<div id="productList">'
for(let i = 0; i < prodList.length; i++) {
prodHtml += `<product :product='prodList[i]'></product>`
}
prodHtml += '</div>'
// append this html to DOM
$('#someWhere').html(prodHtml)
// and now create new Vue instance to replace
// these unknown product tags with real tags
new Vue({
el: '#productList'
})

Dynamic add plus to each row in typescript

I'm working on an ionic2 project which pulls data from and API and displays content of the API to the user which works fine.
But the challenge is i want number the rows in the view as the user scroll down . For example if the API return data of lenght 40, i want to number the rows from 1 to 40.
JS
ionViewDidLoad(){
let loader = this.LoadingController.create({
content: 'Loading Test'
});
loader.present().then(()=>{
this.http
.get('http://localhost/scripts/items.php')
.map(res => res.json()).subscribe(data => {
console.log(JSON.stringify(data));
this.store= data;
for(var i=1;i<data.length;i++) {
this.count = i++;
}
});
loader.dismiss();
});
HTML
<div *ngFor="let item of store">
{{count}}. {{item.Item_Name}}
</div>
You can use index provided by *ngFor directive:
<div *ngFor="let item of store; let i = index">
{{i + 1}}. {{item.Item_Name}}
</div>
More info about this in angular docs:
https://angular.io/api/common/NgForOf#local-variables
There is also a bit different syntax, which is probably now recommended (depends on what version you use, but the first one is still working I think):
*ngFor="let item of store; index as i"
Another approach would be to add indicies to the data in http.get callback:
for(var i = 0; i < data.length; i++) {
data[i].index = i + 1;
}
And then:
<div *ngFor="let item of store">
{{item.index}}. {{item.Item_Name}}
</div>
This could be helpful if you need the index not only in the view. In other case I would recommend to use #martin-adámek suggestion.

Categories

Resources