using v-for for rendering - vue.js

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

Related

Vue Reactivity issue, setting array element property

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

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/

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.

Trying to create a reactive table in Vue but nothing is being displayed on event calls

So I am trying to push data to my table on keyups from my form input. This is the 'threshold' var that you see below.
This is the table structure and Vue code:
<table v-if="threshold > 0 || date2 != ''" class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Full Name</th>
<th scope="col">Paypal Email</th>
<th scope="col">Amount</th>
<th scope="col">Currency</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
<tr v-for="item in response_data">
<th>{{ response_data }}</th>
<td>{{ item.vendor_name }}</td>
<td>{{ item.paypal_email }}</td>
<td>{{ item.amount }}</td>
<td>{{ item.currency }}</td>
<td>{{ item.commission_status }}</td>
</tr>
</tbody>
</table>
Another condition for data to be pulled in and displayed is a date range being selected.
You can see how this works in the Vue code below:
var datepickerOptions = {
sundayFirst: true
}
// install plugin
Vue.use(window.AirbnbStyleDatepicker, datepickerOptions)
var vm = new Vue({
el: '#app',
data: {
date1: '',
date2: '',
threshold: '',
res_num: 0,
response_data: ''
},
methods: {
get_results: function() {
vm.searchcall();
},
searchcall: function () {
let form_data = new FormData;
form_data.append('action', 'payments_rt_search');
form_data.append('date1', this.date1);
form_data.append('date2', this.date2);
form_data.append('threshold', this.threshold);
axios.post(ajaxurl, form_data).then(function(response){
console.log(response.data);
response_data = response.data;
res_num = response_data.count;
});
}
},
})
My problem is that, though data is being pulled in at the right time, and it is the right data, no data is being being pushed to the tables via the for loop.
I'm wondering whether there is something I might be missing here, and would appreciate some input.
Cheers!
You don't change the component data's response_data, just a global variable response_data.
Try to assign vm.response_data and vm.res_.
If you want to use this.resposne_data instead of vm.response_data, you will need to change the then's callback to es6 arrow function like this:
axios.post(ajaxurl, form_data).then(response => {
console.log(response.data);
this.response_data = response.data;
this.res_num = response_data.count;
});
You are assigning a global variable here:
response_data = response.data;
It should be a member variable:
this.response_data = response.data;

How to remove ??? characters on database query result with Laravel

I am have an issue that sounds new and don't know what is happening. I am retrieving data from database with Laravel eloquent.
In my controller:
public function index()
{
$suppliers = Supplier::all();
return response()->json($suppliers);
}
Its working just fine, the problem is the result object however is appearing as shown below with leading ???. All query results in the entire project is rendering just this way. I have tried to trim the project witn trim() but I realize this wont work on object.
����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[{"id":1,"first_name":"Ronald","last_name":"Wekesa","mobile_number":"0717245218","work_phone":"07140000","phone_code":254,"fax":null,"email":"email#yaho.com","postal_address":"P.o
Box
323","town":"Kitale","zip":30200,"phisical_address":"Kiminini","company":"Wafutech","created_at":"2018-03-05
11:52:30","updated_at":"2018-03-05
11:52:30"},{"id":2,"first_name":"Ronald","last_name":"Wekesa","mobile_number":"0725645544","work_phone":"070025400","phone_code":2....
when I render the result in my vuejs front end as shown below I am getting blank loop, I mean the loop runs but with empty bullet list. I am suspecting this might have something with this fun behavior.
//My View component
<template>
<div>
<h3>Suppliers</h3>
<div class="row">
<div class="col-md-10"></div>
<div class="col-md-2">
<router-link :to="{ name: 'create-supplier'}" class="btn btn-primary">Add Supplier</router-link>
</div>
</div><br />
<table class="table table-hover table-striped table-responsive">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Company</td>
<td>Mobile Phone</td>
</tr>
</thead>
<tbody>
<tr v-for="supplier in suppliers">
<td>{{ supplier.first_name }}</td>
<td>{{ supplier.last_name }}</td>
<td>{{ supplier.company }}</td>
<td>{{ supplier.mobile_number }}</td>
<td><router-link :to="{name: 'edit-supplier', params: { id: supplier.id }}" class="btn btn-primary">Edit</router-link></td>
<td><button class="btn btn-danger" v-on:click="deleteSupplier(supplier.id)">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name:'displayAsset',
data(){
return{
suppliers: []
}
},
created: function()
{
this.fetchSuppliers();
},
methods: {
fetchSuppliers()
{
let uri = 'http://localhost/ims/public/api/suppliers';
this.axios.get(uri).then((response) => {
this.suppliers = response.data;
});
},
deleteSupplier(id)
{
let uri = `http://localhost/ims/public/api/suppliers/${id}`;
this.suppliers.splice(id, 1);
this.axios.delete(uri);
}
}
}
</script>
I have tried to re-install laravel but no difference. I have also re-installed my xampp server with the latest version but wan't lucky either. What is causing this and how can I resolve it. Thanks in advance.