VueJs v-for loop an array inside an array - loops

I have a code as
<div v-for="benefit in service.benefits">
<p>{{benefit}}</p>
</div>
and here is the data
service: [
{title: 'blablabla',
price: '123',
benefits: ['a', 'b']},
{title: 'blaaablabla',
price: '12345',
benefits: ['aa', 'bb']},
]
I want to loop the data inside the benefits, but it doesn't work because v-for needs a key and in my case, there's no key for that. Is there any other way to loop this kind of data?
Thank you

you can use v-for inside v for :
var app = new Vue({
el: '#app',
data: {
service: [{
title: 'blablabla',
price: '123',
benefits: ['a', 'b']
},
{
title: 'blaaablabla',
price: '12345',
benefits: ['aa', 'bb']
},
]
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2/dist/vue.js"></script>
<div id="app">
<div v-for="(item, i) in service" :key="i">
<p>{{item.title}}</p>
<p>My Benefits :</p>
<p v-for="(benefit, index) in item.benefits" :key="index">
{{benefit}}
</p>
</div>
</div>

You could flatten benefits and make it a computed property, then iterating through it would be much easier
var app = new Vue({
el: '#app',
data: {
service: [{
title: 'blablabla',
price: '123',
benefits: ['a', 'b']
},
{
title: 'blaaablabla',
price: '12345',
benefits: ['aa', 'bb']
},
]
},
computed: {
benefits: function() {
return this.service.flatMap(({
benefits
}) => benefits)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2/dist/vue.js"></script>
<div id="app">
<div v-for="(benefit, i) in benefits" :key="i">
<p>{{benefit}}</p>
</div>
</div>

Related

Is there a way for me to push my referenced object into an array?

I want to push each object into an array when it is clicked. I am able to get a reference of each individual object but I'm not able to push the object into an array. It tells me push is not a function. I've spent so much time trying to figure this out. Can someone point me in the right direction?
angular.module('app', []);
angular.module('app').controller("MainController", function() {
var vm = this;
vm.ordered = {};
vm.menu = [{
title: 'Pizza',
type: 'entree',
favorite: true,
price: 10
}, {
title: 'Tacos',
type: 'entree',
favorite: false,
price: 5
}, {
title: 'Onion Rings',
type: 'app',
favorite: false,
price: 2
}, {
title: 'Ice Cream',
type: 'dessert',
favorite: false,
price: 11
}, {
title: 'Mac n Cheese',
type: 'app',
favorite: false,
price: 7
}, {
title: 'Salad',
type: 'salad',
favorite: true,
price: 4
}];
}).directive('section', function() {
return {
restrict: 'E',
link: function(scope, element) {
scope.ordered = {};
element.bind('click', function(event) {
console.log(scope.item);
scope.ordered.push(scope.item);
});
}
};
});;
.left {
float: left;
width: 50%;
}
.right {
float: left;
width: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app" ng-controller="MainController as main">
<div class="left">
<h2>Lists One</h2>
<section id="{{item.id}}" ng-repeat="item in main.menu | filter:main.searchInput | orderBy:main.order.key:main.order.reverse">
<strong>{{item.title}} </strong>
<span>$ {{item.price}}</span>
</section>
</div>
<div class="right">
<h2>Lists Two</h2>
<section id="{{item.id}}" ng-repeat="item in main.ordered | filter:main.searchInput | orderBy:main.order.key:main.order.reverse">
<strong>{{item.title}} </strong>
<span>$ {{item.price}}</span>
</section>
</div>
Change scope.ordered = {}; to scope.ordered = [];

Accessing an array within an array (ng-repeat)

I have a data structure like this:
[
{firstName: "John",
secondName: "Smith",
children: ["Fred", "Hannah"]
},
{firstName: "Daniel",
secondName: "Evans",
children: ["Maggie", "Eddie", "Maria"]
}
]
I want to use ng-repeat to return the CHILDREN of each person object, in a continuous list.
Like so:
<ul>
<li>Fred</li>
<li>Hannah</li>
<li>Maggie</li>
<li>Eddie</li>
<li>Maria</li>
</ul>
Can anyone help?
You could reduce your data structure before presenting it to the ng-repeat.
var app = angular.module('myApp', [
'my.controllers'
]);
var controllers = angular.module('my.controllers', []);
controllers.controller('MyController', function($scope) {
var people = [{
firstName: "John",
secondName: "Smith",
children: ["Fred", "Hannah"]
}, {
firstName: "Daniel",
secondName: "Evans",
children: ["Maggie", "Eddie", "Maria"]
}, {
firstName:"Childless",
secondName: "Parent"
},
{
firstName:"Jeff",
secondName: "Pasty",
children: ["Mike"]
}];
$scope.allChildren = people.reduce(function(a, b) { return a.concat(b.children) },[]);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController">
<div ng-repeat='child in allChildren'>{{ child }}</div>
</div>
</div>

My scope apply isn't working correctly

I have tried to research this issue and have had no luck. My ng-repeat doesn't display dynamic content from the controller on the first try. I was told to use a .digest or apply to get angular to hit my page again but I am not quite clear how to implement. From the examples I saw online this should work
var shopItems = angular.module('shopItems', []);
var trophyEarns = angular.module('trophyEarns', []);
var app = angular.module('app', ['shopItems', 'trophyEarns']);
shopItems.controller('shopItemController', function ($scope) {
$scope.shopItems = [{
//id: 01,
name: 'One',
//img: '',
price: '$3.99',
altprice: '1 mile',
desc: 'This is a fake description.',
prog: '50%'
},{
//id: 02,
name: 'Two',
//img: '',
price: '$3.99',
altprice: '1 mile',
desc: 'This is a fake description.',
prog: '50%'
}];
$scope.$apply();
});
trophyEarns.controller('trophyEarnsController', function ($scope) {
$scope.trophyEarns = [{
//id: 01,
name: 'One',
//img: '',
price: '$3.99',
altprice: '1 mile',
desc: 'This is a fake description.',
prog: '50%'
},{
//id: 02,
name: 'Two',
//img: '',
price: '$3.99',
altprice: '1 mile',
desc: 'This is a fake description.',
prog: '50%'
}];
$scope.$apply();
});
Here is a snippet of the html and controller
<div ng-app="app">
<div ng-controller="shopItemController">
<div class="itm" ng-repeat="shopItem in shopItems">
<div class="imag"></div>
<h2>{{ shopItem.name }}</h2>
<div class="hff">Earn it: {{ shopItem.altprice }}</div>
<div class="hf">Buy it: {{ shopItem.price }}</div>
<div class="desc"><div>{{ shopItem.desc }}</div></div>
<div class="prog"><div>{{ shopItem.progress }}</div></div>
</div>
</div>
</div>
But this does nothing and no errors pop up. I am still forced to reload every time I leave and go back to the pages with the controllers to see the dynamic content. Am I using this correctly? Is digest better?

How to bring dynamicaly scope in view

In my controller I have this code:
$scope.lists = [{
listName: 'list1'
}, {
listName: 'list2'
}];
angular.forEach($scope.lists, function(item) {
var listName = item.listName;
$scope[listName] = [{
Name: 'Stefan'
}, {
Name: 'Stefan'
}, {
Name: 'Stefan'
}, {
Name: 'Stefan'
}];
});
The Input from lists cames from a webservice, so the values (list1 and list2) can be different each time i reload the app. I can also more then 2 items in lists.
How can I show the value from $scope[listName] in an ng-repat section in my view?
Thanks for your Help.
Stefan.
You might try something like this:
(function() {
angular.module("myApp", []).controller("controller", ["$scope",
function($scope) {
$scope.lists = [{
listName: "list1"
}, {
listName: "list2"
}];
angular.forEach($scope.lists, function(item) {
var listName = item.listName;
$scope[listName] = [{
Name: "Stefan"
}, {
Name: "Stefan"
}, {
Name: "Stefan"
}, {
Name: "Stefan"
}];
$scope.results = $scope[listName];
});
}
]);
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="myApp">
<div data-ng-controller="controller">
<ul>
<li data-ng-repeat="item in results">{{item.Name}}</li>
</ul>
</div>
</div>

How do you show ng-repeated children of filtered array?

I have a drop-down filtered array, but the array I'd like to use is a little more complex, with nested data, similar to this http://jsfiddle.net/vojtajina/u75us/
I'd like to combine both ideas, but can't figure out why my fiddle doesn't display the 'child nodes'
<div class="col-md-12" ng-controller="App04Ctrl">
<p>Search:
Filter:
<select ng-model="filterItem.store" ng-options="item.name for item in filterOptions.stores">
</select>
Sort:
<select ng-model="sortItem.store" ng-options="item.name for item in sortOptions.stores">
</select>
</p>
<ul>
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter" >Name: {{item.name}} Price: {{item.price}} Location: {{item.location}}</li>
<ul>
<li ng-repeat="package in location.packages">{{package.name}} has services:
<ul>
<li ng-repeat="service in package.services">{{service.name}}</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
angular.js:
var app = angular.module('app04', []);
function App04Ctrl($scope) {
//Contains the filter options
$scope.filterOptions = {
stores: [
{id : 2, name : 'Show All', location: 'All Locations' },
{id : 3, name : 'Ashburn', location: 'Ashburn' },
{id : 4, name : 'San Francisco', location: 'San Francisco' },
{id : 5, name : 'Denver', location: 'Denver' },
{id : 6, name : 'Chicago', location: 'Chicago' },
{id : 7, name : 'Irvine', location: 'Irvine' }
]
};
//Contains the sorting options
$scope.sortOptions = {
stores: [
{id : 1, name : 'Price Highest to Lowest' },
{id : 2, name : 'Price Lowest to Highest' },
]
};
//Mapped to the model to filter
$scope.filterItem = {
store: $scope.filterOptions.stores[0]
}
//Mapped to the model to sort
$scope.sortItem = {
store: $scope.sortOptions.stores[0]
};
//Watch the sorting model - when it changes, change the
//ordering of the sort (descending / ascending)
$scope.$watch('sortItem', function () {
console.log($scope.sortItem);
if ($scope.sortItem.store.id === 1) {
$scope.reverse = true;
} else {
$scope.reverse = false;
}
}, true);
//Custom filter - filter based on the location selected
$scope.customFilter = function (locations) {
if (locations.location === $scope.filterItem.store.location) {
return true;
} else if ($scope.filterItem.store.location === 'All Locations') {
return true;
} else {
return false;
}
};
// Location data
$scope.locations = [{
name: "product1",
price: 198,
location: 'Ashburn',
packages: [{
name: 'Doom Patrol',
services: [{
name: 'Mento'}, {
name: 'Vox'}, {
name: 'Robotman'}]}, {
name: 'Suicide Squad',
services: [{
name: 'King Shark'}]}, {
name: 'Shadowpact',
services: [{
name: 'Zauriel'}, {
name: 'Enchantress'}, {
name: 'Ragman'}, {
name: 'Nightshade'}]}]}, {
name: "product2",
price: 402,
location: 'Chicago',
packages: [{
name: 'Metal Men'}, {
name: 'Legion of Superheroes',
services: [{
name: 'Ultra Boy'}, {
name: 'Kid Quantum'}]}]}, {
name: "product2",
price: 300,
location: 'Denver',
packages: [{
name: 'Freedom Fighters',
services: [{
name: 'Damage'}, {
name: 'Iron Munro'}]}, {
name: 'Birds of Prey',
services: [{
name: 'Huntress'}, {
name: 'Black Alice'}]}]}, {
name: "product2",
price: 1243,
location: 'Irvine',
packages: [{
name: 'The Outsiders'}, {
name: 'Zoo Crew',
services: [{
name: 'Rubberduck'}, {
name: 'Captain Carrot'}]}, {
name: 'The Elite',
services: [{
name: 'Vera Black'}, {
name: 'Manchester Black'}]}, {
name: 'Justice Legion Alpha'}]}
];
}
http://jsfiddle.net/jdacio/Vfx3y/2/
What am I missing? Am I on the right track? is there a better way to do this?
There are two problems that I see in your code above:
[1] Notice that you have closed the <li> tag, thus stopping the nesting of your ng-repeat directive to show the packages and and services of each item location. Simply remove the </li> closing tag and that should solve your first problem.
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter" >
Name: {{item.name}}
Price: {{item.price}}
Location: {{item.location}}
</li> <!-- THIS IS THE PROBLEM!! -->
[2] As what Mosho mentioned, your nested ng-repeat directive is using a location reference which does not exist in the current context of its parent ng-repeat directive. The simplest solution would be to change
<li ng-repeat="package in location.packages">
to
<li ng-repeat="package in item.packages">
The resulting HTML code should be:
<ul>
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter" >
Name: {{item.name}}
Price: {{item.price}}
Location: {{item.location}}
<ul>
<li ng-repeat="package in location.packages">{{package.name}} has services:
<ul>
<li ng-repeat="service in package.services">{{service.name}}</li>
</ul>
</li>
</ul>
</li>
</ul>
Instead of location.packages, it should be item.packages. (or 'location in locations' rather than 'item in locations').
<li ng-repeat="item in locations | orderBy:'price':reverse | filter:customFilter">
...
<li ng-repeat="package in location.packages">
You refer to location, but you declare item in locations.

Resources