AngularJS ng-repeat and controllerAs - javascript

I using simple syntax to show, hide element in ng-repeat
<div ng-controller='MainController as vm'>
<ul>
<li ng-repeat="item in vm.items" ng-click="vm.showItem()">
{{item}}
<span ng-show="show">test</span>
</li>
</ul>
When i was using scope everythink worked fine
$scope.showItem = function(){
this.show=!this.show;
}
But same code with controllerAs doesn't work
vm = this;
vm.showItem = function(){
this.show=!this.show;
}
How can i access to show property of current item in ng-repeat?
Controller as http://plnkr.co/edit/Dbp5fO9OEpV6lFRySYUK?p=preview
$scope http://plnkr.co/edit/ptuySNRXSrA64K1IAng3?p=preview

Get the current this instance from the html like
<li ng-repeat="item in vm.items" ng-click="vm.showItem(this)">
And use it in your controller
vm.showItem = function(_this){
_this.show=!_this.show;
}
The problem you faced is the change of this context
Updated plunker http://plnkr.co/edit/pkxI68sGMXonDOA49EUq?p=preview

Proof of concept:
var app = angular.module('myApp', []);
app.controller('MainController', function() {
vm = this;
vm.items = [];
for (var i = 0; i < 10; i++) vm.items.push({
value: i,
show: false,
showItem: function() {
this.show = !this.show
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MainController as vm">
<ul>
<li ng-repeat="item in vm.items" ng-click="item.showItem()">
{{item.value}}
<span ng-show="item.show">test</span>
</li>
</ul>
</div>
</div>
Than we are going to improve it by extracting showItem method to the Item prototype
Second step - using prototype to less memory consume
var app = angular.module('myApp', []);
app.controller('MainController', function() {
vm = this;
vm.items = [];
for (var i = 0; i < 10; i++) vm.items.push(new Item(i));
function Item(value) {
this.value = value
this.show = false
}
Item.prototype.showItem = function() {
this.show = !this.show
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MainController as vm">
<ul>
<li ng-repeat="item in vm.items" ng-click="item.showItem()">
{{item.value}}
<span ng-show="item.show">test</span>
</li>
</ul>
</div>
</div>
Next step will be extracting Item to angular factory

You need to use vm.show = !vm.show;
vm = this;
vm.showItem = function(){
vm.show=!vm.show;
}

Replace the function definition with.
vm.show = !vm.show;
I have attached the sample code snippet.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script data-require="angular.js#1.5.5" data-semver="1.5.5" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.js"></script>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script>
var app = angular.module('myApp', []);
app.controller('MainController', function () {
vm = this;
vm.items = [];
vm.start = 0;
vm.end = 20;
for (var i = 0; i < 10; i++) vm.items.push(i);
// return vm;
vm = this;
vm.show = true;
vm.showItem = function () {
vm.show = !vm.show;
}
});
</script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller='MainController as vm'>
<ul>
<li ng-repeat="item in vm.items" ng-click="vm.showItem()">
{{item}}
<span ng-show="vm.show">test</span>
</li>
</ul>
</div>
</div>
</body>
</html>

Related

How do I create page items in AngularJS if I know the number of pages?

I am working on a small application that displays a "users" JSON in an HTML5 table. It uses Bootstrap 3 and AngularJS. I want to paginate this table.
I do not have an array to loop through, with ng-repeat. I have a number the number of pages.
With jQuery, I would do:
var pageMax = 10;
var paginationItems = [];
for(var i=0; i<pageMax; i++){
var paginationItem = '<li>' + (i + 1) + '</li>';
paginationItems.push(paginationItem);
}
var paginationSum = paginationItems.reduce((a, b) => a + b, '');
$('.pagination').html(paginationSum);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="text-center">
<ul class="pagination"></ul>
</div>
What is the equivalent of the above for loop in AngularJS?
In angular you would do something like this:
angular.module('app', [])
.controller('Controller', function($scope) {
$scope.pageMax = 10;
$scope.pages = new Array($scope.pageMax);
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<body ng-app="app">
<div ng-controller="Controller">
<div class="text-center">
<h3>Initialized in template:</h3>
<ul class="pagination">
<li ng-repeat="n in [].constructor(pageMax) track by $index">
{{$index+1}}
</li>
</ul>
<h3>Initialized in controller:</h3>
<ul class="pagination">
<li ng-repeat="n in pages track by $index">
{{$index+1}}
</li>
</ul>
</div>
</div>
</body>
You can use ng-repeat do to this.
Notice that when you want to render the HTML you have to use $sce.trustAsHtml for AngularJS to actually render the HTML. You can then use ng-bind-html in the HTML.
var app = angular.module("Dummy", []);
var DummyController = function($scope, $sce) {
var pageMax = 10;
$scope.paginationItems = [];
for (var i = 0; i < pageMax; i++) {
var item = $sce.trustAsHtml('' + (i + 1) + '');
$scope.paginationItems.push(item);
}
}
app.controller(DummyController, ["$scope, $sce", "DummyController"]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div ng-app="Dummy">
<div class="text-center" ng-controller="DummyController">
<ul class="pagination">
<li ng-bind-html="item" ng-repeat='item in paginationItems'></li>
</ul>
</div>
</div>

angular show/hide div outside ng view

trying to hide/show div outside ng-view but can not access it.
main controller
var vm = this;
vm.showMyDiv = false;
html
<body ng-app="app" ng-controller="ManinCtrl as main">
<div ng-show="vm.showMyDiv">
my test div
</div>
<div class="ng-view"></div>
<body>
ng-view controller
var vm = this;
vm.hideLoader = true;
how can I access it, I tried with $scope but it does not work
You're declaring the controller like this ng-controller="ManinCtrl as main" so you need to prefix the properties with main and not vm
<div ng-show="main.showMyDiv">
Working example:
angular.module('app', []).controller('mainCtrl', function() {
var main = this;
main.showMe = false;
main.toggleShow = function() {
main.showMe = !main.showMe;
};
}).controller('ctrl', function() {
var vm = this;
vm.exampleText = "I'm inner text in the controller :)";
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="mainCtrl as main">
<div ng-show="main.showMe">HELLO!!</div>
<hr>
<div ng-controller="ctrl as vm">
<div ng-bind="vm.exampleText"></div>
<button ng-click="main.toggleShow()">Click Here</button>
</div>
</div>

Get an element when using ng-if is undefined. Angular.js

All the default elements are hidden.
$scope.hide=false;
ng-if="hide"
I want it when I click on a link, it shows the corresponding element. But I do not know how to show only the element that corresponds. For example if I click on
<li> section1 </ li>
The element with the 'section1' id must be displayed. After that, I do not know why the element is not found.
Var myEl = angular.element (document.querySelector ('#' + id));
Do this using the ng-if statement.
http://jsfiddle.net/8jmnpn2u/
Thank you very much.
Here is your solution
http://jsfiddle.net/8jmnpn2u/2/
Simply you can do it by $scope variable
Define $scope.currentDiv = "";
and on show function just update $scope.currentDiv
Your HTML code
<body ng-app="myApp" ng-controller="myCtrl">
<nav>
<ul>
<li>section1</li>
<li>section2</li>
<li>section3</li>
</ul>
</nav>
<section id='section1' ng-if="currentDiv == 'section1'">
1
</section>
<section id='section2' ng-if="currentDiv == 'section2'">
2
</section>
<section id='section3' ng-if="currentDiv == 'section3'">
3
</section>
</body>
Angular controller
// the main (app) module
var myApp = angular.module("myApp", ['ui.swiper']);
// add a controller
myApp.controller("myCtrl", function($scope) {
$scope.msg = "hello world";
$scope.currentDiv = "";
$scope.show= function(id){
$scope.currentDiv = id;
}
});
Try this: if you create an array to keep the 'hide' value of yor sections, you can control them independently
<body ng-app="myApp" ng-controller="myCtrl">
<nav>
<ul>
<li>section1</li>
<li>section2</li>
<li>section3</li>
</ul>
</nav>
<section id='section1' ng-if="hide['section1']">
1
</section>
<section id='section2' ng-if="hide['section2']">
2
</section>
<section id='section3' ng-if="hide['section3']">
3
</section>
</body>
the main (app) module
var myApp = angular.module("myApp", ['ui.swiper']);
myApp.controller("myCtrl", function($scope) {
$scope.hide = [];
$scope.show= function(id){
$scope.hide[id] = true;
var myEl = angular.element( document.querySelector( '#'+id ));
}
});
Here's the jsfiddle http://jsfiddle.net/2c71bjuu/

AngularJS manipulate two ng-repeat

I'm calling two times the same list in my HTML5 view.
<div class="list" data-ng-repeat="item in model.items">
<div class=list-item">
{{ item.name }}
<a data-ng-click="addToList(item)">
<span data-ng-hide="item.checked">Add</span>
<span data-ng-show="item.checked">Remove</span>
</a>
</div>
</div>
<div class="checkbox-list" data-ng-repeat="item in model.items">
<div class=list-item">
<input type="checkbox" data-ng-checked="item.checked" data-ng-click="addToList(item)" />
{{ item.name }}
</div>
</div>
In my controller, I'm having the method defined in the scope:
function addToList(item) {
item.checked = !item.checked;
for (var i = 0; i < this.$scope.items.length; i++) {
if (this.$scope.items.id == item.id) {
this.$scope.items[i] = item;
break;
}
}
}
When I click the Addor Remove button, the list has an update, but the checkbox-list item doesn't get checked.
On the other hand, when checking a checkbox, the list doesn't get an update.
How can I make this happen?
Looks like you are using controller as syntax.
So in your js code add the model to the controller itself(assuming you yourController refers to the controller and you have your methods in the controller):
for (var i = 0; i < yourController.items.length; i++) {
if (yourController.items.id == item.id) {
yourController.items[i] = extension;
break;
}
}
Inside YourController declare:
var yourController = this;
Then in the HTML where you declare the controller, declare it as follows:
ng-controller = "YourController as yourController"
And then you can access the items in HTML as:
yourController.items
you are mixing the javascript function declaration syntax with angular
While working with angular you should always angular syntax to get the benefit of synchronization between the model and the view.
$scope.addToList = function(){}
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.model = {};
$scope.model.items = [{"name":"one"},{"name":"two"}]
$scope.addToList = function(item) {
item.checked = !item.checked;
}
});
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div class="list" data-ng-repeat="item in model.items">
<div class="list-item">
{{ item.name }}
<a data-ng-click="addToList(item)">
<span data-ng-hide="item.checked">Add</span>
<span data-ng-show="item.checked">Remove</span>
</a>
</div>
</div>
<div class="checkbox-list" data-ng-repeat="item in model.items">
<div class="list-item">
<input type="checkbox" data-ng-checked="item.checked" data-ng-click="addToList(item)" />
{{ item.name }}
</div>
</div>
</body>
</html>
You are not using function with $scope. This might help:
$scope.addToList = function (item) {
item.checked = !item.checked;
for (var i = 0; i < $scope.items.length; i++) {
if ($scope.items.id == item.id) {
$scope.items[i] = extension;
break;
}
}
}

Nested ng-repeat data not correctly binding to directive

[Edited to reflect comments in #shaunhusain answer]
I have a nested ng-repeat construct for which I want to instantiate a new instance of a directive for every inner item, passing to that directive the data from that inner item. In the code below, I've included two nested loops. The one that works uses one-way binding via the {{ }} notation, and the other appears to work as well...until you hit the Refresh button. Even though $scope.frames changes (and the {{ }} binding continues to reflect the changes), the binding for the directive is not triggered.
What am I missing?
var myApp = angular.module('myApp', []);
myApp.directive("myDirective", function () {
return {
restrict: 'E',
scope: {
boundData: '=data'
},
link: function (scope, element) {
angular.element(element.find("div")[0])
.html('')
.append("<p>" + scope.boundData.val + "</p>");
}
}
});
myApp.controller('FooCtrl', ['$scope', function ($scope) {
$scope.clear = function () {
$(".item-list").empty();
};
$scope.getData = function () {
var frames = [];
for (var i = 0; i < 2; i++) {
var items = [];
for (var j = 0; j < 4; j++) {
items.push({ val : Math.floor(Math.random() * 5000) });
};
frames.push(items);
}
$scope.frames = frames;
};
$scope.getData();
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="myApp">
<div ng-controller="FooCtrl">
<div>
<button ng-click="getData()">Refresh</button>
<button ng-click="clear()">Clear</button>
</div>
<div style="float: left">
<b>{} binding</b>
<div ng-repeat="frame in frames track by $index">
<div ng-repeat="item in frame track by $index">
{{item.val}}
</div>
</div>
</div>
<div style="margin-left: 120px">
<b>Using directive</b>
<div ng-repeat="frame in frames track by $index">
<div ng-repeat="item in frame track by $index">
<my-directive data="item">
<div class="item-list"></div>
</my-directive>
</div>
</div>
</div>
</div>
</div>
"Thinking in AngularJS" if I have a jQuery background?
var myApp = angular.module('myApp', []);
myApp.directive("myDirective", function () {
return {
restrict: 'E',
scope: {
boundData: '=data'
},
link: function (scope, element) {
angular.element(element.find("div")[0])
.html('')
.append("<p>" + scope.boundData.val + "</p>");
}
}
});
myApp.controller('FooCtrl', ['$scope', function ($scope) {
$scope.clear = function () {
$(".item-list").empty();
};
$scope.getData = function () {
var frames = [];
for (var i = 0; i < 2; i++) {
var items = [];
for (var j = 0; j < 4; j++) {
items.push({ val : Math.floor(Math.random() * 5000) });
};
frames.push(items);
}
$scope.frames = frames;
};
$scope.getData();
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="FooCtrl">
<div>
<button ng-click="getData()">Refresh</button>
<button ng-click="clear()">Clear</button>
</div>
<div style="float: left">
<b>{} binding</b>
<div ng-repeat="frame in frames track by $index">
<div ng-repeat="item in frame track by $index">
{{item.val}}
</div>
</div>
</div>
<div style="margin-left: 120px">
<b>Using directive</b>
<div ng-repeat="frame in frames track by $index">
<div ng-repeat="item in frame track by $index">
<my-directive data="item">
<div class="item-list"></div>
</my-directive>
</div>
</div>
</div>
</div>
</div>
Believe your problem is because of using a jquery selector without a specified parent being element. Typically you won't need jQuery when using Angular, good to drop it initially, search on SO for how to think in AngularJS with a jQuery background for a good write up. Will add a sample here shortly.
The flaw here was the use of track by $index in my ng-repeat (specifically the inner one).

Categories