How to get array index from html element? - javascript

Hey In my Vue application I have the opportunity to create several persons:
<div v-for="newContent in temp" :key="newContent.id" #click="showId(newContent.id)" v-show="true">
<!-- Head of part personal data -->
<h4 class="person" style="margin-left: 0.95vw">Person 1</h4>
<!-- Enter Person Data -->
<testmodul1></testmodul1>
<div class="trash">
<button class="btn btn-outline-danger" #click="deletePerson()">Person löschen</button>
</div>
<hr />
</div>
If I want to add more persons, there is a button, which appends more of these person inputs:
<button class="btn btn-outline-secondary" #click="useIt()">Add more persons</button>
useIt(){
this.temp.push({
id:this.id+=1
})
console.log(this.temp);
},
data() {
return {
id:0,
temp:[{
id:0,
}]
};
},
Output of the console.log method in the console (clicked the add button 2 times):
Proxy {0: {…}, 1: {…}, 2: {…}}
[[Handler]]: Object
[[Target]]: Array(2)
0: {id: 0}
1: {id: 0}
length: 2
[[Prototype]]: Array(0)
Now the following problem: Let's say for example we created 3 new persons. Now I recognize, that the second person is false and I want to delete it. When I click on the of person 2 I want to get the array index of the html element. I have already tried this, but it does not really work well:
<div v-for="newContent in temp" :key="newContent.id" #click="showId(newContent.id)" v-show="true">
showId(index){
alert(index);
}
Is there an other way how I could find out the index in the array of the html div I clicked?

Please, check Vue.js list rendering.
You can iterate through array with both element and index like this:
<li v-for="(item, index) in items">
{{ index }} - {{ item.message }}
</li>
For your case:
<div v-for="(newContent, index) in temp" :key="newContent.id" #click="showId(index)" v-show="true">

You can define index variable in v-for loop itself. Like
<div v-for="(person,index) in persons" :key="index">
{{index}} //which is index of current item
</div>

Related

Vue JS: Looping through object inline attribute

I am new to vue.js so this might be an easy question, but I unfortunatelly didnt come to a result on my own.
So this is the basis of my template:
<template v-for="page in $props.data.pageInfo" >
<div class="overviewItem" :key="page.uid" :data-cat=" **looping through the object to get both cat_id's ** ">
<div v-for="(cat, index) in page.categories" :key="index" >
<p v-if="index === 0" class="subtitle">
{{ cat.title }}
</p>
</div>
</div>
</template>
{{ page.categories }} has the following values at the first .overviewItem:
[
{
"cat_id": 1,
"title": "Kategorie 1"
},
{
"cat_id": 2,
"title": "Kategorie 2"
}
]
The loop to get the subtitle works perfectly fine, but I cannot find any option on how to loop through this object so that i get the two values of data-cat attribute.
Use .map to generate a new array of just the cat_id and then join them together with a space in between:
<div
class="overviewItem"
:key="page.uid"
:data-cat="page.categories.map(c => c.cat_id).join(' ')"
>
...
</div>

rendering list of objects in react/mobx

i have a list of objects in my jsx class. Let's assume it's a fixed list of objects for now
versions = [
{owner: "luca", date: "today", fw: "00"},
{owner: "thomas", date: "tomorrow", fw: "00"},
{owner: "peter", date: "yesterday", fW: "00"},];
i'm trying to render the values of these objects in nested div elements on my webpage. basically it's a panel of rows that i represent as divs. here's the html for it
<div className="fc-revisions-sidebar revisions-panel flex-vertical flex-grow-1">
<div className="fc-revisions-sidebar-header fc-revisions-sidebar-header-bg-color-brand">
<div className="fc-revisions-sidebar-title">Version history</div>
</div>
<div className="fc-revisions-sidebar-revisions-list-container">
<div className="fc-revisions-sidebar-revisions-list">
<div role="rowgroup">
<div className="fc-revisions-collapsible-panel" role="button">
<div className="fc-revisions-collapsible-panel-container">
<div className="fc-revisions-row fc-revisions-row-selected" role="row" aria-selected="true" aria-level="1">
<div className="fc-revisions-row-content-wrapper">
<div className="fc-revisions-row-header fc-row-content">
<div className="fc-revisions-row-text-box" rows="1" maxLength="80" aria-multiline="false">
**{version.date}**
</div>
</div>
<div className="fc-revisions-row-content fc-row-content" role="presentation">
<div className="fc-revisions-row-collaborator-list">
<div className="fc-revisions-row-collaborator">
<span className="fc-versions-rown-collaborators-label">Created by **{version.owner}**</span>
<span className="fc-revisions-row-collaborator-name">**{version.fw}**</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
i'm not sure how to implement this in my component class!!
starting from the first div after this one
<div role="rowgroup">
my html code to create each row in the panel starts.
I want to iterate over the objects in my list and create/fill each row in my panel with the right data from that list
I've tried a dozen different ways but nothing is showing up on my webpage. I just don't understand how to iterate over the list of objects in 'versions' and create/fill the panel in progress.
Let assume you have array of objects declared inside render using const. You can iterate the array either using .map, .forEach, for loop etc. In your case I would prefer .map for iteration because map returns new array. So inside the map construct jsx elements and return them.
Now, returned jsx elements will be placed in versionItems array. You can just call that with {} like expression in render return.
render(){
const versions = [
{owner: "luca", date: "today", fw: "00"},
{owner: "thomas", date: "tomorrow", fw: "00"},
{owner: "peter", date: "yesterday", fW: "00"},];
const versionItems = versions.map((item, index) => {
return (
<div key={"key"+index} role="rowgroup">
//just get all your property values here using item.owner, item.date etc
</div>
)
});
return(
<div>
{versionItems}
</div>
)
}
Iteration is normally done by maping an array of values to an array of components. Something like this:
versions = [ ... ]
return (
<div>
<div>Version History</div>
{
versions.map(version =>
<div key={version.date}>
{version.date}
</div>
)
}
</div>
)
Note that for Reacts reconciliation to work properly when potentially re-rendering with a new array of values, the outer element in the array should have a unique key attribute so that React quickly can recognize any removed or added values in the array on the next render.

Array length is incorrect

I have this code:
public toggle(event): void {
console.log(event.currentTarget.parentNode.children);
html:
<div class="activity-header" timeline-item ng-click="vm.toggle($event);">
So when I click the header I pass in the event, grab the parent element and than it's children.
When I check the log I see:
HTMLCollection(2) [div.activity-header, div.activity-footer]
When I click to expand the array in the log I see:
HTMLCollection(2) [div.activity-header, div.activity-footer]
0: div.activity-header
1: div.activity-body
2: div.activity-body
3: div.activity-body
4: div.activity-body
5: div.activity-body
6: div.activity-body
7: div.activity-body
8: div.activity-footer
length: 9
The body elements are rendered from a ng-repeat:
<div ng-repeat="activity in vm.activities.items track by activity.id" class="activity-body">
Just for reference the html structure is like so:
<div>
<div class="activity-header" timeline-item ng-click="vm.toggle($event);">
<i class="material-icons">person</i>
</div>
<div ng-repeat="activity in vm.activities.items track by activity.id" class="activity-body">
<div class="contact-moment">
<i class="material-icons">person</i>
<div class="contact-moment-body">
<b>{{vm.activity.channel | activityChannel}}: <span ng-bind-html="vm.case.title || (vm.activity | activityTitle)"></span></b>
<br />
<div ng-include="'/CustomerService/ActivityTimeline/ActivityTemplates/' + activity.type + '.html'" id="{{activity.type}}"></div>
</div>
</div>
</div>
<div class="activity-footer">
<md-button>
Button 1
</md-button>
</div>
</div>
So the issue is that Javascript doesn't count the activity-body elements while they are there.
That's because when you console.log, the div.activity-body aren't rendered to the DOM yet. When you expand the list of DOM nodes, the body elements have been rendered, and the event.currentTarget.parentNode.children reference has been updated to reflect this.
What's written to the log is just a snapshot - when you interact with it, it gets updated to reflect the real world.
children is a live list and console.log() holds a reference to an object just like most other JavaScript.
The order of events is:
Log children: It has 2 elements in it.
Add 7 more elements to it.
Click the expand icon in the Console which causes the object to be reexamined, so all 9 elements are shown.

Vue JS send data from v-for on button click

I'm new to Vue JS, and i'm having a little problem
i'm looping through an array and i have a button inside the div that i'm looping with
the idea is to get the data of the specified data after the click event
for example let's say i have this array numbers: [1,2,3,4,5] and i'm looping through it like this
<div v-for="number in numbers">
<p>{{ number }}</p>
<button v-on:click="getTheSelectedOne"> Get The Value </button>
</div>
i tried doing so
<button v-on:click="getTheValueOfTheSelectedOne(number)"> Get The Value </button>
but i got an error,
how can i achieve such a result ?
<div v-for="number in numbers">
Should be:
<div v-for="(number, index) in numbers" :key="index">
The following:
<button v-on:click="getTheSelectedOne"> Get The Value </button>
Should be:
<button v-on:click="getTheSelectedOne(number)"> Get The Value </button>
And you must have that method defined:
methods: {
getTheSelectedOne (number) {
// then number will be the number
console.log(number)
}
}

Vue.js change model attached to a form upon clicking a list

I have an array of objects. These objects are loaded into a list in vue.js.
Aside from this list, I have a form that displays data from one of these objects. I want to, when clicking one of the list's elements, it will bind this specific object to the form and show its data.
How can do this in Vue.js?
My list code is:
<div id="app-7">
<ul id="food-list" v-cloak>
<food-item v-for="item in foodList" v-bind:food="item" v-bind:key="item.id" inline-template>
<li class="food">
<div class="food-header">
<img :src="'img/' + food.slug +'.png'">
<div class="food-title">
<p>{{food.name}} |
<b>{{food.slug}}</b>
</p>
<p>quantity: {{food.quantity}}</p>
</div>
<div class="food-load"> // load into form upon clicking this
</div>
</div>
</li>
</food-item>
</ul>
</div>
Since I do not have the code for the form, this is my best guess without clarification.
You can add a click handler to the item you want to be clicked. It will pass the value of the food item into the method.
<div class="food-load" #click="setFoodItem(item)">
</div>
And when that method is called, it can assign the clicked item to a data property. I'm not sure where your form is, and if it is in a different component. If it is in a child component, you would have to pass it in as a prop, or emit an event to pass it to a parent component.
data() {
return {
//create a reactive field to store the current object for the form.
foodItemForm: null
};
},
methods: {
//method for setting the current item for the form.
setFoodItem(item) {
this.foodItemForm = item;
}
}
Missing quite a bit of info in your sample code, your script is very important to see to make sense of what you would like to accomplish and where things might be going wrong.
Here's a quick list of the issue I came across with your code:
v-for refers to an individual food item as 'item', inside the loop you're trying to access properties as 'food'
You don't wrap your code in a component unless you're importing the component
When binding a value to 'v-bind:src' (or shorthand ':src') only pass the url, you should be specifying this in your script not inline.
You're better off using a button and the 'v-on:click' (or shorthand '#click') to load your selected food item into your form
You should also include your Javascript
Regardless, here's how I would handle this (took the liberty in filling in some blanks):
<template>
<div id="app">
<ul id="food-list">
<!--<food-item v-for="item in foodList" v-bind:food="item" v-bind:key="item.id" inline-template>-->
<li v-for="item in foodList" class="food">
<div class="food-header">
<img :src="item.slug" v-bind:alt="item.slug" width="250px" height="auto">
<div class="food-title">
<p>{{item.name}} | <b>{{item.slug}}</b></p>
<p>quantity: {{item.quantity}}</p>
</div>
<button class="food-load" #click="loadFoodItem(item.id)">Load Food Item</button>
</div>
</li>
<!--</food-item>-->
</ul>
<form v-if="activeFoodId != null" id="foodItemForm" action="#">
<h3>Food Form</h3>
<label for="food-id">Id:</label>
<input id="food-id" type="number" v-bind:value="foodList[activeFoodId].id"><br/>
<label for="food-slug">Slug:</label>
<input id="food-slug" type="text" v-bind:value="foodList[activeFoodId].slug"><br/>
<label for="food-name">Name:</label>
<input id="food-name" type="text" v-bind:value="foodList[activeFoodId].name"><br/>
<label for="food-quantity">Quantity:</label>
<input id="food-quantity" type="number" v-bind:value="foodList[activeFoodId].quantity">
</form>
</div>
</template>
<script>
export default {
name: 'app',
data: function () {
return {
activeFoodId: null,
foodList: [
{
id: 1,
slug: 'http://3.bp.blogspot.com/-QiJCtE3yeOA/TWHfElpIbkI/AAAAAAAAADE/Xv6osICLe6E/s320/tomato.jpeg',
name: 'tomatoes',
quantity: 4
}, {
id: 2,
slug: 'https://img.purch.com/rc/300x200/aHR0cDovL3d3dy5saXZlc2NpZW5jZS5jb20vaW1hZ2VzL2kvMDAwLzA2NS8xNDkvb3JpZ2luYWwvYmFuYW5hcy5qcGc=',
name: 'bananas',
quantity: 12
}, {
id: 3,
slug: 'https://media.gettyimages.com/photos/red-apples-picture-id186823339?b=1&k=6&m=186823339&s=612x612&w=0&h=HwKqE1MrsWrofYe7FvaevMnSB89FKbMjT-G1E_1HpEw=',
name: 'apples',
quantity: 7
}
]
}
},
methods: {
loadFoodItem: function (foodItemId) {
console.log(foodItemId)
this.activeFoodId = foodItemId
}
}
}
</script>
<style>
/# Irrelevant #/
</style>
Hope it helps!

Categories

Resources