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/
Related
Vuetify3 newbie here.
I have a table which is filled with v-for for some models. Each row has a v-select that need to fire an event when changed. Something like this:
<tr v-for="payout in payouts" :key="payout.id">
<td>{{ payout.username }}</td>
<td>
<v-select
v-model="payout.status"
#update:modelValue="changeStatus"
:items="['On', 'Off']"
>
</v-select>
</td>
</tr>
If leave function in #update:modelValue="changeStatus" without any parameters, I can get access to selected value in one v-select.
But how I can get selected value AND id of current row simultaneously?
I was thinking about something like #update:modelValue="changeStatus(item, payout.id)". But of course it doesn't work .
Instead of calling changeStatus directly, I would wrap it in a callback which dispatch update:modelValue argument AND payout.id:
<tr v-for="payout in payouts" :key="payout.id">
<td>
<v-select #update:modelValue="val => changeStatus(val, payout.id)">
</td>
</tr>
I omitted some code to make it simpler to grasp.
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
I'm having a reactivity issue in following example. I can't find what I'm doing wrong. Am I setting the vue data correctly or do I need to do something else?
I have an object model as follows;
export default {
data () {
return {
filteredSkillTiers: [{
name: '',
categories: [{
name: '',
recipes: [{ name: '', profit: '' }]
}]
}],
recipeFilterText: ''
}
}
In created() method, I fill this filteredSkillTiers with real data. When I check as console.log(this.FilteredSkillTiers), it seems fine.
And, in my template, I have a button with #click="CalculateRecipe(i, j, k) which seems to be working perfect.
Here is my template;
<div
v-for="(skilltier,i) in filteredSkillTiers"
:key="i"
>
<div
v-if="isThereAtLeastOneFilteredRecipeInSkillTier(skilltier)"
>
<h3> {{ skilltier.name }} </h3>
<div
v-for="(category,j) in skilltier.categories"
:key="j"
>
<div
v-if="isThereAtLeastOneFilteredRecipeInCategory(category)"
>
<v-simple-table
dense
class="mt-3"
>
<template v-slot:default>
<thead>
<tr>
<th class="text-left">{{ category.name }}</th>
<th class="text-left">Click to Calculate</th>
<th class="text-left">Estimated Profit</th>
</tr>
</thead>
<tbody>
<tr v-for="(recipe,k) in category.recipes" :key="k">
<template
v-if="recipe.name.toLowerCase().includes(recipeFilterText.toLowerCase())"
>
<td>{{ recipe.name }}</td>
<td>
<v-btn
dense
small
#click="CalculateRecipe(i, j, k)"
>
Calculate
</v-btn>
</td>
<td>{{ filteredSkillTiers[i].categories[j].recipes[k].profit }}</td>
</template>
</tr>
</tbody>
</template>
</v-simple-table>
</div>
</div>
</div>
</div>
And here is my method;
CalculateRecipe (skilltierIndex, categoryIndex, recipeIndex) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('profitResult')
}, 50)
}).then((profit) => {
this.filteredSkillTiers[skilltierIndex].categories[categoryIndex].recipes[recipeIndex].profit = 'new Profit'
console.log(this.filteredSkillTiers[skilltierIndex].categories[categoryIndex].recipes[recipeIndex].profit)
})
},
When I log to console, I can see that I'm modifying the object correctly. But my updated value is not reflected in the rendered page.
There is this thing I suspect, if I update an irrevelant component in this page (an overlaying loading image component), I can see that rendered table gets updated. I want to avoid that because updating a component returns me to top of the page.
<td>{{ filteredSkillTiers[i].categories[j].recipes[k].profit }}</td>
This profit property seems not reactive. I'm really confused and sorry that I couldn't clear the code more, Thanks.
Here's the article describing how exactly reactivity works in Vue 2.x. And yes, (in that version) you should never update a property of tracked object directly (unless you actually want the changes not to be tracked immediately).
One way (mentioned in that article) is using Vue.set() helper function. For example:
Vue.set(this.filteredSkillTiers[skilltierIndex]
.categories[categoryIndex].recipes[recipeIndex], 'profit', 'new Profit');
You might consider making this code far less verbose by passing recipe object inside CalculateRecipe function as a parameter (instead of those indexes), then just using this line:
Vue.set(recipe, 'profit', promiseResolutionValue);
I have this html code
<tr v-for="(help, index) in helps">
<td scope="row">{{ help.ID }}</td>
<td scope="row">{{ help.Date | formatDateWithTime }}</td>
<td>
<p #click="fullTextFun(index)" v-show="help.FullText">{{ help.Text.substring(0,16) + '...' }}</p>
<p #click="fullTextFun(index)" v-show="!help.FullText">{{ help.Text }}</p>
</td>
</tr>
I want to be able to show the full text when someone click on the current p element. This is my vue function
fullTextFun: function(index) {
this.helps[index].FullText = !this.helps[index].FullText;
},
It doesn't work. I also tried to do it using this code
<span #click="fullTextFun(help)" v-show="help.FullText">{{ help.Text.substring(0,16) + '...' }}</span>
fullTextFun: function(item) {
item.FullText = !item.FullText;
},
But again without any luck. It seems the v-show function don't care about the status of help.FullText
When I load the data I don't have FullText variable in my helps array. I don't know if this is the problem
This is what it is inside my helps variable when first loaded
[{"ID":"2","Date":"2019-05-15
17:27:29","Text":"randomText"},{"ID":"4","Date":"2019-05-17
09:53:59","Text":"some text"}]
It might be Vue reactivity issue.
fullTextFun: function(index) {
this.helps[index].FullText = !this.helps[index].FullText;
this.helps = JSON.parse(JSON.stringify(this.helps))
}
Basically Vue only updates if you change the reference.
When you update this.helps[index].FullText, this.helps still points to old object reference, and Vue can't recognize the change.
Another solution is using Vue.set
Vue.set(this.helps[index], 'FullText', !this.helps[index].FullText)
You can read more at Vue document
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.