I have an object that holds both known and unknown values. Quantity is unknown, Type is known. I want to present the user inputs for every Type and the user enters quantity. How do I model this in Vue?
data() {
return {
message: "",
order: {
orderDetails: [], // end result, after user made choices: [{ quantity: 1, productType: "A"}, {quantity: 1 , productType :"B"}] ,
},
productType: ["A", "B", "C", "D"],
};
},
and
<ul>
<li v-for="(item, index) in productType" :key="index">
<input type="number" v-model="?order.orderDetails[index].quantity?" /> {{ item }}
</li>
</ul>
and the desired output is kinda like this
<ul>
<li><input type="number"> A </li>
<li><input type="number"> B </li>
<li><input type="number"> C </li>
<li><input type="number"> D </li>
</ul>
obviously this is not working cos the vmodel object doesn't exist. I don't think that initialising the model with null quantities is the correct approach as the Types will be coming from an API call and will not be hardcoded. Is a computed property the solution?
It is best to structure your data model to reflect the view. If you keep the product types and the quantities separate, then you're going to have a difficult time trying to pair them together in the view because the data will be all over the place.
You want to have a list of inputs for each type, so your data model can be an array of objects where each object has a productType property and a quantity property. Initially each quantity will be 0.
data() {
return {
orderDetails: [
{ productType: 'A', quantity: 0 },
{ productType: 'B', quantity: 0 },
{ productType: 'C', quantity: 0 },
{ productType: 'D', quantity: 0 },
]
}
}
But let's say you don't know what the types will be ahead of time (perhaps you fetch the types from some API), so you can't structure the data like that straight away in the code like I have shown. So then all you have to do is dynamically construct the orderDetails array once you have the array of types:
data() {
return {
orderDetails: []
}
},
async created() {
// Fetch the types from some hypothetical API
const types = await fetchTypes()
// Populate the orderDetails array from the types
this.orderDetails = types.map(type => ({
productType: type,
quantity: 0,
}))
}
Now it's just a 1-to-1 mapping between the data and the view!
<ul>
<li v-for="(item, index) in orderDetails" :key="index">
<input type="number" v-model="item.quantity">
{{ item.productType }}
</li>
</ul>
Your view (template) should be very simple with no complex data processing; it should be just a simple function of the data.
Related
I have a table in which I have particular column as checkboxes. I have assigned a empty list. So what I want is that I want the ids of the rows of the enabled checkboxes. Say for example if the checkboxes are enabled in id 4 and 5 then the list should be [4,5]
Sample data:
{ id:1,
name: "A",
qty: 6,
value: 10
},
{ id:2,
name: "B",
qty: 4,
value: 10
},
{ id:3,
name: "C",
qty: 1,
value: 10
}
Getting data from service:
ngOnInit(): void {
this.dataService.getData().subscribe(res => {
this.listes = res;
});
}
List name:
checkboxselectlist: any[];
My stackblitz: https://stackblitz.com/edit/angular-ivy-4vnwed?file=src%2Fapp%2Fapp.component.ts
This should help you.
You need to pass an event handler to ngchange.
In the event handler, you can get the element id which should help you to update your list. checkboxselectlist
// in your app.component.ts
filterResults(obj: any, e: any) {
console.log(obj);
console.log(e.currentTarget.checked); // true or false
// UPDATE LIST HERE
}
// in your app.component.html
<tr *ngFor="let list of listes; index as i">
<td>{{i+1}}</td>
<td>{{list.name}}</td>
<td>{{list.qty}}</td>
<td>{{list.value}}</td>
<td> <input type="checkbox" id="vehicle1"
name="vehicle1"
(change)="filterResults(list, $event)">
</td>
</tr>
I'm developing a Vue app and I have a list of movies like this:
movies [
{name: 'spider-man', id: 3},
{name: 'thor'},
{name: 'x-men', id: 7}
]
and this is my template
<ul>
<li v-for="movie in movies" :key="movie.name">{{movie.name}}</li>
</ul>
I only wanna show the movies who has an ID, in this case, thor shouldn't be shown. I've tried with v-if but I got this error: "The 'movies' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'".
Thanks, hope you can help me!
Computed properties to the rescue:
data: () => ({
movies: [
{name: 'spider-man', id: 3},
{name: 'thor'},
{name: 'x-men', id: 7}
]
})
...
computed: {
moviesWithId() {
return this.movies.filter(movie => movie.id)
}
}
...
In your template
<ul>
<li v-for="movie in moviesWithId" :key="movie.name">{{movie.name}}</li>
</ul>
Or you may add condition to render to your li tags like v-show="movie.id"
Or filter your dataset like :
<li v-for="movie in movies.filter(movie => movie.id)" :key="movie.name">{{movie.name}}</li>
kinda new to vue, I have mapped out some data from my initial data object in vue.js I am trying to hide and show only the items within that iteration of the mapping when the user selects the heading. I am using the isHidden prop in vue to hide and show my list items but when selecting any heading it shows all the tags instead of those associated with that specific header.
anyone know the proper way to do this? should I use some index or id from e.target? or should I give each list item a 'hidden' property and change it that way somehow?
here's my list that I mapped out
<div v-for="item in list">
<h4 v-on:click="viewItemsinCat()">{{item.category}}</h4>
<ul>
<li v-if="!isHidden" v-for="item in item.food">
{{item}}
</li>
</ul>
</div>
then I have my data like so:
data: {
list: [{
category: 'Baked goods',
food: ['bread', 'cookie', 'butter', 'powder']
}, {
category: 'meats',
food: ['chicken', 'turkey', 'beef']
}, {
category: 'fruits',
food: ['bannana', 'apple', 'pineapple']
}, {
category: 'canned goods',
food: ['tomatoes', 'green beans', 'corn']
}, {
category: 'veggies',
food: ['broccoli', 'celery', 'lettuce']
}, {
category: 'pantry',
food: ['broom', 'mop', 'dried beans']
}, ],
isHidden: true,
}
then I have my method to alter isHidden
viewItemsinCat: function(){
this.isHidden = false
},
Add a selected property to contain the currently selected item when the user clicks:
data() {
return {
selected: null,
list: [...]
}
}
<div v-for="item in list">
<h4 v-on:click="selected=item.category">{{item.category}}</h4>
<ul v-if="selected==item.category">
<li v-for="food in item.food">
{{ food }}
</li>
</ul>
</div>
Here's a demo
how render items with groups by date in Vue.js?
eg: I have an array of dynamic data like which will come from api with following type :
items: [
{
name: 'a',
created: '2019-02-03T02:31:46.3485544'
},
{
name: 'b',
created: '2019-02-03T02:31:46.3485544'
},
{
name: 'c',
created: '2019-02-03T02:31:46.3485544'
},
{
name: 'd',
created: '2019-02-04T02:31:46.3485544'
},
{
name: 'd',
created: '2019-02-04T02:31:46.3485544'
}
]
and i want to render list like that:
<p> items created today </p>
<ul>
<li v-for="item in items">{{item.name}}</li>
</ul>
<p> items created yesterday </p>
<ul>
<li v-for="item in items">{{item.name}}</li>
</ul>
<p> items created February 2 </p>
<ul>
<li v-for="item in items">{{item.name}}</li>
</ul>
<p> items created February 4 </p>
<ul>
<li v-for="item in items">{{item.name}}</li>
</ul>
It's possible to do? I will receive this data always from api so it will be dynamic data, It's mean i will need to titles too get dynamically, i mean eg: items created February 4... items created February 3.. items created today etc.
You could create a computed property to group your data by day:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data() {
return {
items: [{
name: 'a',
created: '2019-02-03T02:31:46.3485544'
},
{
name: 'b',
created: '2019-02-03T02:31:46.3485544'
},
{
name: 'c',
created: '2019-02-03T02:31:46.3485544'
},
{
name: 'd',
created: '2019-02-04T02:31:46.3485544'
},
{
name: 'd',
created: '2019-02-04T02:31:46.3485544'
}
]
}
},
computed: {
groupByDay() {
let g = {};
this.items.forEach(item => {
let d = item.created.substring(0, 10);
if (g[d]) {
g[d].push(item.name);
} else {
g[d] = [];
g[d].push(item.name);
}
});
return g;
}
}
});
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app" class="container">
<div v-for="(item,key,index) in groupByDay">
<h5>items created : {{key}}</h5>
<ul>
<li v-for="name in item">{{name}}</li>
</ul>
</div>
</div>
Essentially you need to obtain array of arrays so you will iterate over the items.
It would be awesome if API could return the data grouped for you, so you can just iterate over it.
If you don't have that luxury, you need to group the data yourself. I'd recommend using https://date-fns.org/ for determining which group the item should go to.
I am trying to use ng-repeat to iterate through an array of objects and use each objects ID to look up the data binded to a checklist model.
I have the following javascript object in a project I'm working on:
{
diagnosis: {
mainfractures: [
{
id: "metacarpal",
textinput_id: "metacarpal_text",
title: "5th Metacarpal",
},
{
id: "proximal_phalanx",
textinput_id: "proximal_phalanx_text",
title: "Proximal Phalanx",
},
{
id: "middle_phalanx",
textinput_id: "middle_phalanx_text",
title: "Middle Phalanx",
},
{
id: "distal_phalanx",
textinput_id: "distal_phalanx_text",
title: "Distal Phalanx",
},
{
id: "scaphoid_fracture",
textinput_id: "scaphoid_fracture_text",
title: "Scaphoid Fracture",
}
]
}}
Here is what I have for my checklist model. As the user selects a checkbox, a value is binded to the array associated with that fracture.
$scope.checklists = {
"diagnosis": {
metacarpal: [],
proximal_phalanx: [],
middle_phalanx: [],
distal_phalanx: [],
scaphoid_fracture: []
}
}
Checklist Image Example
Once a users makes a selection similar to the image above the the checklist model for metacarpal should look like this: metacarpal: ["head"]
What I'm trying to do is list each of the users selection in bulletpoint via fracture.id. I'm trying to accomplish it with this piece of code but it's only listed the fracture title so far. is it a problem with trying to interpolate fracture.id into ng-repeat?
<div ng-repeat="fracture in diagnosis.mainfractures">
<div > <!--ng-if="checklists['diagnosis'][fracture.id] > 0"-->
<h4>{{ fracture.title }}</h4>
<div class="row">
<ul type="disc">
<li ng-repeat="selection in checklists['diagnosis'][fracture.id]">
• {{ capitalize(selection) }}
</li>
</ul>
</div>
</div>
</div>
Based on your supplied code, I'd have to say your issue is actually due to JS syntax errors. You're missing commas after each object item and there is a random double quote here scaphoid_fracture"[].
$scope.checklists = {
"diagnosis": {
metacarpal: []
proximal_phalanx: []
middle_phalanx: []
distal_phalanx: []
scaphoid_fracture"[]
}
}
Here is a fully working jsfiddle
Adjusted the code a bit:
capitalize ->
uppercase(https://docs.angularjs.org/api/ng/filter/uppercase)
some syntax errors
But seems that access by dynamic object key inside ng-repeat works pretty correct
https://jsbin.com/rodecosoyo/1/edit?html,js,output
Angular Application
var app = angular.module('arrayid', []);
app.controller('arrayContainerCtrl', function($scope) {
$scope.diagnosis = {
mainfractures: [{
id: "metacarpal",
textinput_id: "metacarpal_text",
title: "5th Metacarpal",
}, {
id: "proximal_phalanx",
textinput_id: "proximal_phalanx_text",
title: "Proximal Phalanx",
}, {
id: "middle_phalanx",
textinput_id: "middle_phalanx_text",
title: "Middle Phalanx",
}, {
id: "distal_phalanx",
textinput_id: "distal_phalanx_text",
title: "Distal Phalanx",
}, {
id: "scaphoid_fracture",
textinput_id: "scaphoid_fracture_text",
title: "Scaphoid Fracture",
}]
};
$scope.checklists = {
"diagnosis": {
metacarpal: ['1', '2'],
proximal_phalanx: ['2', '3'],
middle_phalanx: ['3'],
distal_phalanx: ['4'],
scaphoid_fracture: ['5']
}
};
});
Markup:
<body ng-app='arrayid' ng-controller='arrayContainerCtrl'>
<div ng-repeat="fracture in diagnosis.mainfractures">
<h4>{{ fracture.title }}</h4>
<div class="row">
<ul type="disc">
<li ng-repeat="selection in checklists['diagnosis'][fracture.id]">
• {{ selection | uppercase }}
</li>
</ul>
</div>
</div>
</body>