Optimize the number of ng-repeat |angularJS - javascript

I want to separate everything in my code according to predefined levels given , from level 1 to level 6 , now my JSON reads
$scope.myJson=[{
id: 1,
level: 1,
name: "any name"
},
{
id: 2,
level: 2,
name: "any name"
},
{
id: 3,
level: 2,
name: "any name"
}....]
now in my HTML I have written something like
<div>level 1
<div ng-repeat="prod in myJson" ng-if="prod.level==1">{{prod.name}}
</div>
</div>
<div>level 2
<div ng-repeat="prod in myJson" ng-if="prod.level==2">{{prod.name}}
</div>
</div>
and so on , I want to use only one ng-repeat to filter all the results in HTML on basis of the levels , as the results number in thousands the app is taking too much of time to respond

You could try a switch case in your ng repeat, for example :
<div ng-repeat="prod in myJson">
<div ng-switch-on = "prod.level">
<div ng-switch-when="1">
Level 1 {{prod.name}}
</div>
<div ng-switch-when="2">
Level 2 {{prod.name}}
</div>
<div ng-switch-default>
Another level {{prod.name}}
</div>
</div>
</div>
So you will only do one run over your data.

To make it more generic, groupBy will solve this for you.
Demo:
angular.module('app', ['angular.filter'])
.controller('myCtrl', function($scope) {
$scope.myJson = [{
id: 1,
level: 1,
name: "any name level1"
}, {
id: 2,
level: 2,
name: "any name level2"
}, {
id: 3,
level: 2,
name: "any name level2"
}, {
id: 4,
level: 2,
name: "any name level2"
}, {
id: 5,
level: 1,
name: "any name level1"
}, {
id: 6,
level: 3,
name: "any name level3"
}]
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>
</head>
<body>
<div ng-controller="myCtrl">
<ul ng-repeat="(key, value) in myJson | groupBy: 'level'">
Level- {{ key }}
<li ng-repeat="item in value">
{{ item.name }}
</li>
</ul>
</div>
</body>
</html>

Related

VueJS - Checkbox "checked" attribute is inconsistent with its state

This is a simple todo-list example, where I'd like the checkboxes to be checked or not, depending on the task being completed or not.
After unchecking a checkbox under the "Complete tasks" section, the next checkbox will appear unchecked, even though it's still checked in the "All tasks" section.
To reproduce easily, uncheck "Go to the store" in the "Complete tasks" section. "Clean room" will appear unchecked, even though it's still checked in "All tasks", and still completed in the data.
How can I fix this ?
<html>
<head>
<title>VueJS</title>
</head>
<body>
<div id="root">
<h1>All tasks</h1>
<ul>
<li v-for="task in tasks">
{{ task.description }}
<input type="checkbox" v-model="task.completed" :id="task.id">
</li>
</ul>
<h1>Complete tasks</h1>
<ul>
<li v-for="completeTask in completeTasks">
{{ completeTask.description }}
<input type="checkbox" v-model="completeTask.completed" :id="completeTask.id">
</li>
</ul>
<h1>Incomplete tasks</h1>
<ul>
<li v-for="incompleteTask in incompleteTasks">
{{ incompleteTask.description }}
<input type="checkbox" v-model="incompleteTask.completed" :id="incompleteTask.id">
</li>
</ul>
</div>
<script src="https://unpkg.com/vue#2.6.12/dist/vue.js"></script>
<script>
new Vue({
el: '#root',
data: {
tasks: [
{id: 1, description: 'Go to the store', completed: true},
{id: 2, description: 'Finish X', completed: false},
{id: 3, description: 'Do Y', completed: false},
{id: 4, description: 'Clear inbox', completed: false},
{id: 5, description: 'Make Z', completed: false},
{id: 6, description: 'Clean room', completed: true},
],
},
computed: {
completeTasks() {
return this.tasks.filter(task => task.completed);
},
incompleteTasks() {
return this.tasks.filter(task => !task.completed);
},
},
});
</script>
</body>
</html>
The issue is that Vue is trying to be smart and "reuse" the DOM. But in this case it will work against you.
To fix this you need add a key to each element with a v-for, this way Vue can track which <li> is which based on the key.
It's explained more in-depth on the docs:
https://v2.vuejs.org/v2/guide/list.html#Maintaining-State
<html>
<head>
<title>VueJS</title>
</head>
<body>
<div id="root">
<h1>All tasks</h1>
<ul>
<li v-for="task in tasks" :key="task.id">
{{ task.description }}
<input type="checkbox" v-model="task.completed" :id="task.id">
</li>
</ul>
<h1>Complete tasks</h1>
<ul>
<li v-for="completeTask in completeTasks" :key="completeTask.id">
{{ completeTask.description }}
<input type="checkbox" v-model="completeTask.completed" :id="completeTask.id">
</li>
</ul>
<h1>Incomplete tasks</h1>
<ul>
<li v-for="incompleteTask in incompleteTasks" :key="incompleteTask.id">
{{ incompleteTask.description }}
<input type="checkbox" v-model="incompleteTask.completed" :id="incompleteTask.id">
</li>
</ul>
</div>
<script src="https://unpkg.com/vue#2.6.12/dist/vue.js"></script>
<script>
new Vue({
el: '#root',
data: {
tasks: [
{id: 1, description: 'Go to the store', completed: true},
{id: 2, description: 'Finish X', completed: false},
{id: 3, description: 'Do Y', completed: false},
{id: 4, description: 'Clear inbox', completed: false},
{id: 5, description: 'Make Z', completed: false},
{id: 6, description: 'Clean room', completed: true},
],
},
computed: {
completeTasks() {
return this.tasks.filter(task => task.completed);
},
incompleteTasks() {
return this.tasks.filter(task => !task.completed);
},
},
});
</script>
</body>
</html>

Add Prev/Next buttons in multiple items array in AngularJS (ngRepeat)

I want to create a multiple items slider to list some players using ng-repeat (Angular 1.6). I'd like to add a prev/next buttons in the ul>lis to access the next or previous player in the array, shifting the view item by item.
HTML----sliderdemo.html
<div ng-controller="SliderDemoCtrl">
<div class="champions-slider">
<ul class="team-members list-inline text-center" style="display:flex" >
<li ng-repeat="player in players | limitTo: 4" style="padding:10px">
<div class="img-holder">
<img ng-src="{{ player.image }}" alt="{{player.name}}" width="20px">
</div>
<strong class="name">{{ player.name }}</strong>
</li>
</ul>
Prev
Next
</div>
</div>
My controller js---slider.demo.controller.js
var myApp = angular.module('slider.demo', []);
myApp.controller('SliderDemoCtrl',['$scope',function($scope){
$scope.players = [
{
image:"http://placehold.it/500/e499e4/fff&text=1",
name: "tes 1"
},
{
image:"http://placehold.it/500/e499e4/fff&text=2",
name: "tes 2"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 3"
},
{
image:"http://placehold.it/500/e499e4/fff&text=4",
name: "tes 4"
},
{
image:"http://placehold.it/500/e499e4/fff&text=5",
name: "tes 5"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 6"
}
];
}]);
Here is a plunkr of the question: https://plnkr.co/edit/J7dxeMfM22ju5gpZl5ri?p=preview
Any help would be greatly appreciated.
Thx!
I think you are searching like below solution :
// Code goes here
var myApp = angular.module('slider.demo', []);
myApp.controller('SliderDemoCtrl',['$scope',function($scope){
$scope.players = [
{
image:"http://placehold.it/500/e499e4/fff&text=1",
name: "tes 1"
},
{
image:"http://placehold.it/500/e499e4/fff&text=2",
name: "tes 2"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 3"
},
{
image:"http://placehold.it/500/e499e4/fff&text=4",
name: "tes 4"
},
{
image:"http://placehold.it/500/e499e4/fff&text=5",
name: "tes 5"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 6"
},
];
$scope.size=0;
$scope.next=function(){
if($scope.size+4==$scope.players.length)
return;
$scope.size+=1;
}
$scope.prev=function(){
if($scope.size==0)
$scope.size=0;
else
$scope.size-=1;
}
}]);
<!doctype html>
<html ng-app="slider.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="SliderDemoCtrl">
<div class="champions-slider">
<ul class="team-members list-inline text-center" style="display:flex" >
<li ng-repeat="player in players | limitTo: 4" style="padding:10px">
<div class="img-holder">
<img ng-src="{{ players[$index+val].image }}" alt="{{players[$index+val].name}}" width="20px">
</div>
<strong class="name">{{ players[$index+size].name }}</strong>
</li>
</ul>
Prev
Next
</div>
</div>
</body>
</html>
You can handle the pagination by ng-if using a $index.Just go through Plunker
$scope.pre = 0;
$scope.nex = 4;
$scope.nextItem = function(){
$scope.pre = $scope.nex;
$scope.nex = $scope.nex + 4;
}
$scope.prevItem = function(){
$scope.nex = $scope.pre
$scope.pre = $scope.pre - 4;
}

Knockout.js {{each}} not listing items in javascript template

I've created a simple app that should iist each item from a model in a list, created using a javascrit template.
Fiddle
Html:
<div id="tagsList" class="box">
<div class="box-head">
<h2 class="left">Tags</h2>
</div>
<div class="box-content">
<input type="text" placeholder="Add New Tag" />
<button>+ Add</button>
<div data-bind="template: 'tagsTempl'"></div>
</div>
</div>
<script id="tagsTempl" type="text/html">
<ul>
{{each tags}}
<li class="tagItem">
<span>${Name}</span>
<div>
Edit
Delete
</div>
</li>
{{/each}}
</ul>
</script>
Javascript:
$(function () {
//$("#tagDialog").hide();
var data = [
{ Id: 1, Name: "Ball Handling" },
{ Id: 2, Name: "Passing" },
{ Id: 3, Name: "Shooting" },
{ Id: 4, Name: "Rebounding" },
{ Id: 5, Name: "Transition" },
{ Id: 6, Name: "Defense" },
{ Id: 7, Name: "Team Offense" },
{ Id: 8, Name: "Team Defense" }
];
var viewModel = {
tags: ko.observableArray(data),
tagToAdd: ko.observable(""),
addTag: function() {
this.tags.push({ Name: this.tagToAdd() });
}
}
ko.applyBindings(viewModel)
});
Output of list:
{{each tags}}
${Name}
Edit Delete
{{/each}}
The scripts file is accessible through viewing source. I'm not sure where my error is. Any help?
I updated your fiddle. Now it is working like you want it to: The list of tags is being rendered using the knockout standard method as described in the docs.
HTML
<ul data-bind="template: {name: 'tagsTempl', foreach: tags}"></ul>
Template
<script id="tagsTempl" type="text/html">
<li class="tagItem">
<span data-bind="text: Name"></span>
<div>
Edit
Delete
</div>
</li>
</script>
Also I connected the viewmodel to the view.
For example:
<button data-bind="click: addTag">+ Add</button>
You simply forgot most of it. I suggest you follow the interactive tutorials on how to do this.

custom directive in angularjs

My custom directive is not working:
html:
<body ng-controller="StoreController as store">
<ul class="list-group">
<li class="list-group-item" ng-repeat="product in store.products">
<div>
<h3>
<product-title></product-title>
</h3>
...
javascript.app:
...
app.directive('productTitle', function(){
return {
restrice: 'E',
templateUrl: 'product-title.html'
};
});
...
and my product-title.html:
{{product.name}}
<em class="pull-right"> {{product.price | currency}}</em>
in my html page i cant see the product name and product price.
I am new in this subject :)
what should i do to make it work?
please help me.
++thanks everyone for yours answers, it is works! i tried for 3 days to find an answer.. and you did it in 5 min.. thanks! :)++
Couple of issues:
restrict is spelled wrong
Templates for html should have one root, so you should do something like this
<div>
{{product.name}}
<em class="pull-right"> {{product.price | currency}}</em>
</div>
Here is the complete running code for your directive in this JSBin
JS
angular
.module('app', [])
.controller('AppController', function ($scope) {
$scope.store = {
products: [
{ id: 1, price: 132, name: 'abc' },
{ id: 2, price: 127, name: 'def' },
{ id: 3, price: 112, name: 'mno' },
{ id: 4, price: 145, name: 'xyz' }
]
};
})
.directive('productTitle', function(){
return {
restrict: 'E',
templateUrl: 'product-title.html'
};
});
HTML
<div ng-controller='AppController'>
<ul class="list-group">
<li class="list-group-item" ng-repeat="product in store.products">
<h3>
<product-title></product-title>
</h3>
</li>
</ul>
</div>
<script id="product-title.html" type="text/ng-template">
{{product.name}}
<em class="pull-right"> {{product.price | currency}}</em>
</script>

How to append scope.value as HTML?

I am currently writing an AngularJS application, and I would like to append or make the value under $scope as an HTML tag value instead of a regular value.
HTML:
<div gridster="gridsterOptions">
<ul>
<li gridster-item="widget" ng-repeat="widget in dashboard.widgets" class="main-dashboard-container">
<div class="box" ng-controller="CustomWidgetCtrl">
<div class="box-header main-dashboard-header">
<h4>{{ widget.name }}</h4>
<div class="box-header-btns pull-right">
<a title="settings" ng-click="openSettings(widget)"><i class="glyphicon glyphicon-cog"></i></a>
<a title="Remove widget" ng-click="remove(widget)"><i class="glyphicon glyphicon-trash"></i></a>
</div>
</div>
<div class="box-content main-dashboard-content">{{ widget.content }}</div>
</div>
</li>
</ul>
</div>
AngularJS Code:
$scope.dashboards = {
'1': {
id: '1',
name: 'Home',
widgets: [{
col: 0,
row: 0,
sizeY: 1,
sizeX: 1,
name: "URL Filter",
content:'<div class="table-responsive " ng-controller="URLFilterCategoriesController as viewAll"><table class="table table-hover"><thead><tr><td>Categories</td><td>Hits</td></tr></thead><tbody><tr ng-repeat="urlfil in viewAll.urlfiltercat"><td>{{urlfil.category}}</td><td>{{urlfil.hit}}</td></tr></tbody></table></div>'
}, {
col: 2,
row: 1,
sizeY: 1,
sizeX: 1,
name: "Widget 2"
}]
},
As you can see under the AngularJS code, I've added series of html codes and that I would like it to be appended/added as HTML inside my HTML codes. Thanks!
Use the ng-bind-html directive
You might want to look at these two links:
https://docs.angularjs.org/api/ng/directive/ngBindHtml
With ng-bind-html-unsafe removed, how do I inject HTML?

Categories