Vue JS send data from v-for on button click - javascript

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)
}
}

Related

How to get json data from model in angular

Tried to get JSON data from the model but it is not working. Only it is working when i use this.products.allproduct['product1'];. But in my application, I am passing the object name. So, depends on passing object name data will appear.
If i use this.products.allproduct[prd]; not working. How to resolve this issue.
app.component.html:
<button (click)="getData('product1')">Product 1</button>
<button (click)="getData('product2')">Product 2</button>
<button (click)="getData('product3')">Product 3</button>
<div>
{{showData}}
</div>
app.component.ts:
getData(prd: string|number) {
this.showData = this.products.allproduct[prd];
}
demo: https://stackblitz.com/edit/angular-ivy-kng5nw?file=src%2Fapp%2Fapp.component.ts
Its array of objects and showing correctly.
Use ngFor for loop on the inner array.
<div *ngFor="let row of showData;let i = index;">
{{row.name}}
</div>

Bind pair of array element

I have 8 values in an Array. I am trying to bind two values in a row. Next two in next row and vice versa. But I couldn't do that in *ngFor. Please help me out.
TS
times = ["7.00 AM","8.00 AM","10.00 AM","11.00 AM","1.00 PM","2.00 PM","4.00 PM","5.00 PM"]
HTML
<div *ngFor="let time of times">
<button class="btn btn-outline">{{time}}</button>
</div>
But, displays one in each.
Expected output
Use index to get the next value in the array
<div *ngFor="let time of times; let i = index;">
<button
*ngIf="times[i + 1]"
class="btn btn-outline"
>{{time}} - {{times[i + 1]}}</button>
</div>

Conditionally hide the nth element of a v-for loop without modifying the array. vue 3 composition api search function

I have a ref variable (foxArticles ), which holds a list that contains 100 items. In a v-for loop i loop over each value. As a result, i have 100 values rendered on the page.
<template>
<div class="news_container">
<div
v-for="article in foxArticles"
v-bind:key="article"
class="article_single_cell"
>
<div
class="news_box shadow hover:bg-red-100 "
v-if="containsKeyword(article, keywordInput)"
>
<div class="news_box_right">
<div class="news_headline text-red-500">
<a :href="article.url" target="_blank">
{{ article.title }}
</a>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
const foxArticles = ref([]);
</script>
I also have a search function, which returns the value, if it includes the passed in keyword. The function is used in the child of the v-for loop.
<div class="search_input_container">
<input
type="text"
class="search_input"
v-model="keywordInput"
/>
</div>
<script>
const keywordInput = ref("");
function containsKeyword(article, keywordInput) {
if (article.title.toLowerCase().includes(keywordInput.toLowerCase())) {
return article;
}
}
</script>
The problem is, i can't use .slice() on the foxArticles array in the v-for loop, because that screws up the search functionality, as it returns only the values from the sliced range.
How can i have the access the all of the values of the array, while not rendering all 100 of returned articles on the initial load?
Any suggestions?
I think your approach will make it incredibly complex to achieve. It would be simpler to always iterate over some set, this set is either filtered based on a search-term, or it will be the first 100 items.
I'm not very familiar yet with the Vue 3 composition api so I'll demonstrate with a regular (vue 2) component.
<template>
<div class="news_container">
<div
v-for="article in matchingArticles"
v-bind:key="article"
class="article_single_cell"
>
... news_box ...
</div>
</div>
</template>
<script>
export default {
...
computed: {
matchingArticles() {
var articles = this.foxArticles;
if (this.keywordInput) {
articles = articles.filter(article => {
return this.containsKeyword(article, this.keywordInput)
})
} else {
// we will limit the result to 100
articles = articles.slice(0, 100);
}
// you may want to always limit results to 100
// but i'll leave that up to you.
return articles;
}
},
....
}
</script>
Another benefit is that the template does not need to worry about filtering results.
ok, so i kind of came up with another solution, for which you don't have to change the script part...
instead of having one v-for loop , you can make two of them, where each one is wrapped in a v-if statement div
The first v-if statement says, If the client has not used the search (keywordInput == ''), display articles in the range of (index, index)
The second one says = If the user has written something (keywordInput != ''), return those articles.
<template>
<div class="news_container">
<!-- if no search has been done -->
<div v-if="keywordInput == ''">
<div
v-for="article in foxArticles.slice(0, 4)"
v-bind:key="article"
class="article_single_cell"
>
<div class="news_box shadow hover:bg-red-100 ">
<div class="news_box_right">
<div class="news_headline text-red-500">
<a :href="article.url" target="_blank">
{{ article.title }}
</a>
</div>
</div>
</div>
</div>
</div>
<!-- if searched something -->
<div v-else-if="keywordInput != ''">
<div
v-for="article in foxArticles"
v-bind:key="article"
class="article_single_cell"
>
<div
class="news_box shadow hover:bg-red-100 "
v-if="containsKeyword(article, keywordInput) && keywordInput != ''"
>
<div class="news_box_right">
<div class="news_headline text-red-500">
<a :href="article.url" target="_blank">
{{ article.title }}
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
im not sure how this impacts performance tho, but that's a problem for another day

Pipe to allow multiple filter values simultaneously - Angular

Buttons are generated using *ngFor bringing back as many different types of values available to filter by. I'm filtering on a key of 'location', therefore if there are locations of 'west' and 'england' then two buttons of 'west' and 'england' are available to filter by.
What I want to be able to do is select more than one filter. If I click 'england' all the results for 'england' come back, then if I click 'west' then 'west' comes back as well as 'england' still being "active". Currently, I can only click one filter at a time.
I think I need to assign an active class to my button then this will push an array of whats active to send to my pipe to do the filtering... ?
My filter Button
<div ngDefaultControl [(ngModel)]="filteredLocation" name="locationFilter" id="locationFilter">
<button value="All" class="m-2 btn btn-primary" type="button">All</button>
<button [class.active]="selectedIndex === i" (click)="filteredLocation = entry.location" class="m-2 btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique; let i = index">{{entry.location}}</button>
</div>
single filter on results
<div class="timeline">
<my-timeline-entry *ngFor="let entry of timeLine | filter:filteredLocation:'location'" timeEntryHeader={{entry.year}} timeEntryContent={{entry.detail}} timeEntryPlace={{entry.place}} timeEntryLocation={{entry.location}}></my-timeline-entry>
</div>
I have created a stackBlitz of what I've got - try clicking on a filter you will see only one filter can be applied at one time. https://stackblitz.com/edit/timeline-angular-7-nve3zw
Any help here would be awesome. Thanks
There can be multiple ways to do that one would be to attach some property to determine if location is active for example isLocationActive
Then toggle this flag as per your need and to apply active class also you don't need filter pipe in that case
So your html will look like
<div class="form-group row">
<div ngDefaultControl [(ngModel)]="filteredLocation" name="locationFilter" id="locationFilter">
<button value="All" class="m-2 btn btn-primary" (click)="activeAllEntries()" type="button">All</button>
<button [class.active]="entry.isLocationActive" (click)="entry.isLocationActive = !entry.isLocationActive" class="m-2 btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique; let i = index">{{entry.location}}</button>
</div>
</div>
<div class="timeline">
<ng-container *ngFor="let entry of timeLine">
<my-timeline-entry *ngIf="entry.isLocationActive" timeEntryHeader={{entry.year}} timeEntryContent={{entry.detail}} timeEntryPlace={{entry.place}} timeEntryLocation={{entry.location}}></my-timeline-entry>
</ng-container>
</div>
TS function
activeAllEntries() {
this.timeLine.forEach(t=> t.isLocationActive=!t.isLocationActive)
}
working Demo

Ability to toggle True/False with ( v-if ) in the loop

I am asking about hiding and showing an element in Vue.js
I always use this
<ele v-if="value" />
and then set {value} in Vue Instance data object, then toggle True/False for toggle visible, but now in my situation , my v-if condition put in some element , then this element create with v-for directive
some thing like this
<div v-for="item in items" >
<ele v-if="value" :key="item.i" />
<ele v-if="value" :key="item.i" />
<ele v-if="value" :key="item.i" />
// this button fire a method for Change (toggle) value (used for v-if)
<button #click="ToggleValue" > update </button>
</div>
In my view i have a table contain some rows and each rows have some field ( all field have v-if directive ) and in each rows we have button for fire method
Now what is my question ?!!
At the end my table is doing this , when click on every button ToggleValue method execute and toggle value of (value) object , now all field in all rows change the value ( all thing doing right :D )
but I want click on every button in each row just change the value of that row
I have dummy way
< ele v-if="value(item.id)" />
.........
.........
<button #click="ToggleValue(itme.id)" >
if my index of loop is Const and static I use this way , but now items in loop are dynamic
all thing was in my pen at here , thanks for give me your time
https://codepen.io/hamidrezanikoonia/pen/OQGrPB?editors=1100
Instead of having a single value, turn value into an object (or array) and index it by item.id.
Updated codepen: https://codepen.io/acdcjunior/pen/MQRZmK?editors=1010
In your pen, the JavaScript:
...
],
update_:false
},
methods: {
set_update() {
this.update_ = !this.update_;
}
}
becomes:
...
]
update_: {1: false, 2: false, 3: false}
},
methods: {
set_update(id) {
this.update_[id] = !this.update_[id];
}
}
And the template:
<td :key="getValue.id+4" v-if="update_" mode="in-out" > {{ getValue.rate_curr }} </td>
...
<button #click="set_update()" type="button" class="btn btn-primary"> Update </button>
becomes:
<td :key="getValue.id+4" v-if="update_[getValue.id]" mode="in-out" > {{ getValue.rate_curr }} </td>
...
<button #click="set_update(getValue.id)" type="button" class="btn btn-primary"> Update </button>

Categories

Resources