Vue.js 'if - else' not working with font awesome - vue.js

Here is my code:
<tr v-for="(i, index) in items.data">
<td>{{ index }}</td>
<td>{{ i.name }}</td>
<td>{{ i.producer }}</td>
<td><font-awesome-icon v-if="i.recieved" icon="check" /><font-awesome-icon v-else icon="times" /></td>
</tr>
I received data from server, where i.recieved can be true or false, but when I compile this, I always see only icon times. It is very strange because I have 4 received fields with true on my server.
So what do you think I should do?
In console I see only one error:
error: Elements in iteration expect to have 'v-bind:key' directives (vue/require-v-for-key) at src/views/Home.vue:15:7:
> 15 | <tr v-for="(i, index) in items.data">
| ^

As the warning says, you need to add a key. https://v2.vuejs.org/v2/guide/list.html#key
Try this.
<tr v-for="(i, index) in items.data" :key="index">
<td>{{ index }}</td>
<td>{{ i.name }}</td>
<td>{{ i.producer }}</td>
<td><font-awesome-icon v-if="i.recieved" icon="check" /><font-awesome-icon v-else icon="times" /></td>
</tr>

Your console errors comes because your v-for has no key defined.
It is recommended to provide a key with v-for whenever possible, unless the iterated DOM content is simple, or you are intentionally relying on the default behavior for performance gains.
Since it’s a generic mechanism for Vue to identify nodes, the key also has other uses that are not specifically tied to v-for, as we will see later in the guide.
More Info about the Key

Related

using v-for for rendering

i am build a laravel vue appliction and i want to render my categories from my categoriescontroller
heres my categorycontroller
public function index()
{
// geeting all the categories
$categories = Category::all();
return response([ 'categories' => CategoryResource::collection($categories), 'message' => 'Retrieved successfully'], 200);
}
heres my category.vue file
<tbody>
<tr v-for="category in categories.data" :key="category.id">
<td>{{ category.id }}</td>
<td>{{ category.name }}</td>
<td>11-7-2014</td>
<td><span class="tag tag-success">Approved</span></td>
</tr>
</tbody>
here also is my method in my category.vue file for loading my categorys
loadCategory(){
axios.get("api/category").then(({ data }) => (this.categories = data));
},
now i dont have any errorrs but its not rendering my categories either. please in need of assistance
since you're destructing the response inside the callback parameters .then(({ data }) you should directly render categories without .data field :
<tr v-for="category in categories" :key="category.id">
as you sending the data from laravel using api resource the actual data is loaded inside a data property. so you should extract it like this in the axios call
loadCategory(){
axios.get("api/category").then(({ data }) => (this.categories = data.categories.data));
},
yes i just quickly want to clearify , just incase someones sees this issue both answers from #Boussadjra Brahim and #sazzad was helpfull . so what i did was
first i took #Boussadjra Brahim suggestion and changed this
<tr v-for="category in categories" :key="category.id">
<td>{{ category.id }}</td>
<td>{{ category.name }}</td>
<td>11-7-2014</td>
<td><span class="tag tag-success">Approved</span></td>
</tr>
then i still got errors until i tried #sazzad suggestion but took out the .data attribute giving me this
loadCategory(){
axios.get("api/category").then(({ data }) => (this.categories = data.categories));
},
hope this helps someone also thanks again

Vue checkbox not updating with data change

Having problems with my data in Vue updating the UI, but only checkboxes seem to have this problem.
I'm trying to allow only one checkbox to be checked at one time, therefore I'm setting all the checkboxes to false upon clicking one of them. However, this works in the data but isn't rendered correctly in the checkboxes.
HTML:
<table class="buildings-modify--table table-full table-spacing">
<thead>
<tr>
<th>Name</th>
<th>Primary</th>
<th>Address</th>
<th>City/Town</th>
<th>Province</th>
<th>Postal Code</th>
<th>Phone</th>
<th>Active</th>
</tr>
</thead>
<tbody>
<tr v-for="landlord in selectedLandlords" :key="landlord.id">
<td>{{ landlord.name }}</td>
<td>
<input type="checkbox" :value="landlord.is_primary" #change.prevent="makePrimaryLandlord(landlord)">
</td>
<td>{{ landlord.address }}</td>
<td>{{ landlord.city }}</td>
<td>{{ landlord.province}}</td>
<td>{{ landlord.postal_code}}</td>
<td>{{ landlord.phone }}</td>
<td>{{ landlord.is_active ? "Yes" : "No" }}</td>
</tr>
</tbody>
Vue Code:
export default {
data: function() {
return {
selectedLandlords: []
}
},
methods: {
makePrimaryLandlord: function(landlord) {
this.selectedLandlords = this.selectedLandlords.map(item => {
item.is_primary = false; return item});
}
}
}
}
Only the checkbox appears to have an issue. If I change say the name, or a text value with a filtered array setting them all to a specific value they change but the checkboxes data change doesn't reflect in the UI, however the data in Vue is correct.
From Official docs
text and textarea elements use value property and input event;
checkboxes and radiobuttons use checked property and change event;
select fields use value as a prop and change as an event.
Use :input-value instead of :value
I can't exactly make it up from your code, but are you sure the property is_primary is available in the objects on load of the viewmodel? So for example this.selectedLandlords.push({ Name:'John', is_primary: false, ...}) should contain the is_primary field to make it reactive.
If not, you should use Vue.set(item, 'is_primary', false) to make it reactive.
try using the key attributes to re-render the checkbox.
reference: https://michaelnthiessen.com/force-re-render/

Vuetify access Vue instance data with v-for in v-data-table

How to access the Vue instance data using v-for inside Vuetify's v-data-table
Issue: Data not displayed under Table Header 2
<v-data-table
:headers="headers"
:items="tabular.table" :hide-actions="true"
class="elevation-1"
>
<template v-slot:items="props" v-for="(table, index) in tabular.table" >
<td :class="{'warn' : warning(index)}">{{ props.item.name }}</td>
<td v-for="inner in table.inner" :class="{'warn' : !inner.data}">{{ props.item.inner.data }}</td>
</template>
</v-data-table>
tabular:{table: [
{
name: 'Table Data 1',
inner: [{data: "false"}]
}
fiddle:
https://jsfiddle.net/m09uLgaz/1/
You are supposed to use
<template v-slot:items="props" v-for="(table, index) in tabular.table">
<td :class="{'warn' : warning(index)}">{{ props.item.name }}</td>
<td v-for="inner in props.item.inner" :class="{'warn' : !inner.data}">{{ inner }}</td>
</template>
Instead of
<td v-for="inner in table.inner" :class="{'warn' : !inner.data}">{{ props.item.inner.data }}</td>
You don't need to use props.item.inner because you have that reference in inner. Also in the object inner use true and false as Boolean and not as string.
Edited JSFiddle link https://jsfiddle.net/0pw3264a/
Updated fiddle for custom sort https://jsfiddle.net/qtLujh0e/

VueJS / Vuetify - Possible to dynamically load a data table without having to hard-code the columns?

Good day,
In trying to learn VueJS I wanted to make a generic Vuetify Data Table that could receive an array of objects with n properties, where n is unknown.
Every example and article I've found about using these tables hard-codes the object properties into their headers and items slots, something like this:
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.calories }}</td>
<td class="text-xs-right">{{ props.item.fat }}</td>
<td class="text-xs-right">{{ props.item.carbs }}</td>
<td class="text-xs-right">{{ props.item.protein }}</td>
</template>
Which is fine if I have 1 or 2 datasets. But what if I want to load one of 100 different datasets into my data-table? Do I really need 100 different "foo-table" components with hard-coded values?
How do I handle the template interpolation that would allow me to reuse a single data-table component that could handle data like:
items: [{ name: 'foo', age: 100, occupation: 'retired' }, ...]
and
items: [{ seq: '1234', data: 'XYZ', flag: 'N', operator: 'someone', }, ...]
and correctly v-for each <tr> by the item and the <td> by each item parameter as dictated by the headers (where item[n][header[i].value])?
What I've done so far.
I've spent a fair amount of time on this and the best I came up with is something like the following:
<template slot='items' slot-scope='props'>
<tr v-for='(item, i_index) in items' :key='i_index'>
<td v-for='(header, h_index) in headers' :key='h_index'>
{{ items[i_index][header.value] }}
</td>
</tr>
</template>
But it doesn't work because it's producing items.length-times as many rows because I think the items slot is already implicitly doing a v-for inside of it, making my <tr v-for ...> redundant.
Does anyone have any better ideas on how I can accomplish a generic data-table?
I think the items slot is already implicitly doing a v-for inside of
it.
That's correct, and you only one loop for each row:
<template slot="items" slot-scope="props">
<td v-for="header in headers">{{ props.item[header.value] }}</td>
</template>
See this adapted pen from vuetify site. https://codepen.io/anon/pen/daQbrE?&editable=true&editors=101

how to reduce time to display a list (json object fetched from database) in a table using *ngFor structural directive?

I am fetching a json object using web API, and displaying it in a table using *ngFor Structural Directive. However the problem is, though the object gets fetched instantly and display in console, it takes time to display it in table. I want the object to be displayed in table instantly as soon as it comes into console.
component.html file;
<tr *ngFor="let data of orgData" id="{{data.Id}}">
<td hidden><input type="number" id="1" value="{{ data.Id }}"></td>
<td>{{ data.OrganisationName }}</td>
<td>{{ data.ContactPerson }}</td>
<td>{{ data.ContactPersonHPNo }}</td>
<td>{{ data.ContactPersonEmailId }}</td>
<td>{{ data.SubscriptionStatus }}</td></tr>
component.ts file;
ngOnInit() {
// making use of web API
this.httpService.get('http://url/StudyExAPI/GetOrganisations?Id=').subscribe(
data => {
this.orgData = data as string[];
// console.log(this.orgData);
},
(err: HttpErrorResponse) => {
console.log(err.message);
}
);}
If you have a lot of objects inside your array, you can use the virtual scroll viewport provided by package #angular/cdk which render only visible elements.