I want to display only the first element in ng-repeat and by click display the rest elements.
That's what I tried to do without success:
<button data-ng-click="term = !term">Show rest</button>
<div data-ng-repeat="y in mQues track by $index" data-ng-show="term" data-ng-init="term = $first">
...
</div>
it really display only the first but the button click do noting for some reason...
Change your ng-show condition: data-ng-show="term || $first"
try this...
<div data-ng-repeat="item in items" data-ng-show="term || $index == 0">{{item.title}}</div>
<div data-ng-repeat="y in mQues track by $index" data-ng-if="$first"></div>
I think this will help
Using the angular filter limitTo it is rather straight forward.
function MyCtrl($scope) {
$scope.items = [
{ title: "item 1" },
{ title: "item 2" },
{ title: "item 3" },
{ title: "item 4" }
]
$scope.limit = 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
<span ng-click="limit = limit == 1 ? items.length : 1">Toggle</span>
<ul>
<li ng-repeat="item in items | limitTo:limit" ng-bind="item.title"></li>
</ul>
</div>
https://docs.angularjs.org/api/ng/directive/ngShow
ng-show displays an element by evaluating the expression given to it.
the expression assigned to ng-show gets converted to true or false depending on whether the result is 'truthy' or 'falsy'. When you assign term a truthy value, ng-show is assigned true.
when you do click button, it evaluates term = !term and term then becomes false and therefore the whole div will be hidden
Guess simpler and more straight forward:
var app = angular.module('app', []);
app.controller('DisplayController', function($scope) {
$scope.ShowRest = 0;
$scope.items = [{
title: 'myTitle1'
}, {
title: 'myTitle2'
}, {
title: 'myTitle3'
}, {
title: 'myTitle4'
}, {
title: 'myTitle5'
}];
});
app.$inject = ['$scope'];
Then:
<div data-ng-controller="DisplayController">
<div data-ng-repeat="item in items">
<div data-ng-class="{'no-display': !$first}">{{ item.title }}</div>
</div>
<div data-ng-repeat="item in items" data-ng-show="ShowRest">
<div data-ng-class="{'no-display': $first}">{{ item.title }}</div>
</div>
<button data- ng-click="ShowRest = !ShowRest">Show rest</button>
</div>
Maybe it's not the most efficient way of doing it, but it works!
Fiddle: http://jsfiddle.net/cb6pggL8/1/
Related
Is it possible to hide the row of ng-repeat using ng-if condition?
We are trying to restrict the displaying the ng-repeat row using ng-if condition. Here, I'm checking for the value five and three if it is not there then I need to hide the row.
angular
.module('myApp', [])
.controller('TodoCtrl', function($scope) {
$scope.comments = [{
type: 'one'
}, {
type: 'two'
}, {
type: 'three'
}, {
type: 'four'
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="TodoCtrl">
<table>
<tr ng-repeat="data in comments">
<td ng-if="data.type == 'five' ">five</td>
<td ng-if="data.type == 'three' ">Three</td>
</tr>
</table>
</div>
</div>
Output:
five Three five Three five Three five Three
Expected output:
Three Three Three Three
It's always preferred to initialize your angular module with a name instead of making it blank.
The ngIf directive removes or recreates a portion of the DOM tree
based on an {expression}. If the expression assigned to ngIf evaluates
to a false value then the element is removed from the DOM, otherwise a
clone of the element is reinserted into the DOM. For more details see
below snippet... More information ngif
var myApp = angular.module('myApp', []);
myApp.controller('TodoCtrl', function($scope) {
$scope.comments = [
{
type: 'one'
}, {
type: 'two'
}, {
type: 'three'
}, {
type: 'four'
}
]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div ng-app="myApp" ng-controller="TodoCtrl">
<div >
<table>
<tr ng-repeat="data in comments">
<td ng-if="data.type == 'five'"> five </td>
<td ng-if="data.type == 'three'"> Three </td>
</tr>
</table>
</div>
</div>
Yes, you can use multiple directives on the same element, thus achieving your desired output. Have a look at this example in which, on the same element, I placed ngRepeat, ngIf, ngClick and ngBind.
angular
.module('myApp', [])
.controller('MyCtrl', function() {
this.myList = [1, 2, 3, 4, 5, 6, 7, 8, 9];
this.showNum = function(num) {
console.log('You clicked on', num);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
</head>
<div ng-app="myApp">
<div ng-controller="MyCtrl as vm">
<ul>
<li ng-repeat="listItem in vm.myList"
ng-if="listItem % 2 === 0"
ng-click="vm.showNum(listItem);"
ng-bind="listItem"></li>
</ul>
</div>
</div>
I think that u did not add five in your comment array
$scope.comments = [ {type:'one'},{type:'two'},{type:'three'},{type:'four'},{type:'five'} ]
I am learning inherited/isolated scopes in angular directives and struck with some basic concepts. please see the plunker below.
Example.
Scenario1:
I have 2 directives (book and details). I am displaying two "Book Details" containers and toggling book name by sending custom attributes like this.
<book bookdetails="book" collapsed="yes" list="list"></book>
<book bookdetails="book1" collapsed="no" list="list"></book>
Question: Is this the right way to handle displaying things in 2 different containers?
Scenario 2:
I want to hide the author details section in container 1 but show in container2 on load. How to accomplish that?
When I use this line below it will hide and show both author details section but I want to keep it separate.
<details collapsed="yes"></details>
I know I am lacking basic skills using inherited/isolated scopes. Can someone educate me?
It's OK to use nested directives like you've used so you can do everything related to the details pane in the details controller like removing items from the books list.
If you wouldn't do any logic in details controller and just include some html I would just use ng-include.
Some points I've detected during improving your code:
Template markups are partial html files, so no need to add header, body etc. Just add your markup that you need in your directive.
I've created one model array books that you can iterate with ng-repeat and not two separate scope variables. That's easier to add more books.
I wouldn't pass the collapsed state to directive isolated scope. I would add it to the book model then you can have independent states of the details panes.
You could also create a collapsed array scope variable separate from your model and use it like ng-hide='collapsed[$index]' if you don't like to add it to your model.
Don't compare to the string yes. It makes things more complicated. It's better to use true or false.
The list you're passing is OK if you'd like to use one list for every details pane. But I think you need them independent from each other so add it to your book model.
For toggeling a value you can use the js shorthand: collapsed = !collapsed;. It takes the value of collapsed and inverts it and re-asigns it to collapsed.
Details directive: You don't need to pass attributes to a directive that doesn't use isolated scope. Instead you can directly use the inherited scope of the parent.
Note: I think you should have a look at angular-ui-bootstrap and use an accordion instead of your manually created panes later. But for learning directives your code is OK.
Please have a look at your updated code below or in this plunker.
If something is not clear, feel free to add a comment and I'll try to help.
angular.module('plunker', [])
.controller('MainCtrl', function($scope) {
$scope.books = [{
id: 0,
name: 'Building modern ASP.NET 5',
author: {
name: 'name1',
age: 31,
country: 'USA'
},
collapsed: false,
list: [{
id: 0,
name: 'book1'
}, {
id: 1,
name: 'book2'
}, {
id: 2,
name: 'book3'
}]
}, {
id: 1,
name: 'AngularJS',
author: {
name: 'name2',
age: 27,
country: 'USA'
},
collapsed: true,
list: [{
id: 0,
name: 'book1'
}, {
id: 1,
name: 'book2'
}, {
id: 2,
name: 'book3'
}]
}];
//$scope.list = ["book1", "book2", "book3"];
}).directive('book', function() {
return {
restrict: 'E',
templateUrl: 'book.html',
scope: {
bkdet: "=bookdetails"
//list: "="
//collapsed: "#"
},
controller: function($scope) {
$scope.toggleDetails = function() {
$scope.bkdet.collapsed = !$scope.bkdet.collapsed;
updateCaption();
};
function updateCaption() {
$scope.hypshowhide = $scope.bkdet.collapsed ? 'show details' : 'hide details';
}
// first run
updateCaption();
/*if ($scope.collapsed == 'yes')
{
$scope.dethide = true;
}
else {
$scope.dethide = false;
} */
//$scope.hypshowhide = 'show details';
}
}
})
.directive('details', function() {
return {
restrict: 'E',
templateUrl: 'details.html',
controller: function($scope) {
/*console.log($scope.bkdet.collapsed);
if (!$scope.bkdet.collapsed) { //== 'yes') {
$scope.dethide = true;
}
else {
$scope.dethide = false;
}*/
$scope.removeItem = function(index) {
$scope.bkdet.list.splice(index, 1);
}
}
}
})
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="plunker">
<div ng-controller="MainCtrl">
<div class="container">
<book bookdetails="book" ng-repeat="book in books"></book>
</div>
</div>
<script type="text/ng-template" id="book.html">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h1>Book Details</h1>
</div>
<div class="panel-body">
<a class="pull-right" href="#" ng-click="toggleDetails(collapsed)">{{hypshowhide}}</a>
<div>
<!--ng-hide="dethide">-->
{{bkdet.name}}
</div>
<!--<details collapsed="no"></details>-->
<details></details>
</div>
</div>
</div>
</script>
<script type="text/ng-template" id="details.html">
<div class="container" ng-hide="bkdet.collapsed">
<div class="row">
<ul class="list-group list-unstyled">
<!--<li>
<h1>Author:</h1>
</li>
<li>
<ul>-->
<li>
<strong>Author</strong>
{{bkdet.author.name}}
</li>
<li>
<strong>Age</strong>
{{bkdet.author.age}}
</li>
<li>
<strong>Country</strong>
{{bkdet.author.country}}
</li>
<li>
<div ng-if="bkdet.list.length == 0">
<p>No books here!</p>
</div>
<div ng-repeat="c in bkdet.list">
<p>
{{c.name}}
<button class="btn btn-danger" ng-click="removeItem($index)">X</button>
</p>
</div>
</li>
<!--</ul>
</li>-->
</ul>
</div>
</div>
</script>
</div>
My directive works fine, but I'd like to use it in ng-click However, the function inside link can't be triggered.
http://jsfiddle.net/ovzyro1f/
<div ng-app="editer" ng-controller="myCtrl" class="container">
<div class="parents">
<div ng-repeat="item in items" class="wrap" sibs>
<span>{{item.name}}</span>
<button ng-click="">click</button>
</div>
</div>
</div>
JS
function myCtrl($scope) {
$scope.editedItem = null;
$scope.items = [{
name: "item #1",
thing: "thing 1"
}, {
name: "item #2",
thing: "thing 2"
}, {
name: "item #3",
thing: "thing 3"
}];
$scope.show = false; //ignore this line
}
var editer = angular.module('editer', []);
editer.directive('sibs', function() {
return {
link: function(scope, element, attrs) {
element.bind('click', function() {
element.parent().children().addClass('unclicked');
element.removeClass('unclicked');
})
scope.myClick = function() {
element.parent().children().addClass('unclicked');
element.removeClass('unclicked');
}
},
}
});
I'd like to call the function in ng-click please see this one http://jsfiddle.net/ovzyro1f/2/ to remove sib from div ng-repeat="item in items" class="wrap"
<button ng-click="myClick()">click</button>
You should avoid to manipulate the DOM like we do in jQuery.
In Angular we think differently: it's the data which transforms automatically the DOM when the data changes (https://docs.angularjs.org/guide/databinding). Most of the time you never have to make the changes manually.
In doing so, you generally don't need to use the link function. You can have a controller (like in your example) or a directive with a controller (https://docs.angularjs.org/guide/directive).
Finally I just modified a little bit your controller and your template.
HTML
<div ng-app="editer" ng-controller="myCtrl" class="container">
<div class="parents">
<div ng-repeat="item in items" class="wrap" sibs>
<span ng-class="{ unclicked: !item.selected }">{{ item.name }}</span>
<button ng-click="selectItem(item)">click</button>
</div>
</div>
</div>
JS
function myCtrl($scope) {
$scope.items = [...];
$scope.selectItem = function (item) {
// reset all the items
$scope.items.forEach(function (i) {
i.selected = false;
});
// set the new selected item
item.selected = true;
}
}
Is it possible to achieve dynamic array name, something like friends+$index. For example:
ng-repeat="friend in {{'friends'+$index}}"
The aim is to loop through different arrays: friends1 & friends2.
I tried everything, any combination, but without success. I also never came across to appropriate answers.
Thanks in advance.
You can do something like this.
http://jsfiddle.net/jigardafda/gw7f1qq0/1/
HTML
<div ng-app="myapp">
<div ng-controller="MyCtrl">
<div ng-repeat="(name, value) in frndslist">
{{name}}
<div ng-repeat="item in value.list">
{{item}}
</div>
</div>
</div>
</div>
JS
var myApp = angular.module('myapp',[]);
myApp
.controller('MyCtrl', function ($scope, $rootScope) {
$scope.frndslist = {
'friend1': {
name: 'x1 frnd',
list: [
"1.some1",
"1.some2"
]
},
'friend2': {
name: 'x2 frnd',
list: [
"2.some1",
"2.some2"
]
}
};
});
Here's another solution:
The HTML:
<div ng-app="App" ng-controller="AppController as controller">
<ul ng-repeat="friend in friends[index]">
<li>{{friend}}</li>
</ul>
</div>
Javascript:
var application = angular.module("App",[]);
application.controller("AppController",function($scope){
friends1 =["Name1", "Name2", "Name3", "Name4"];
friends2 =["Name5", "Name6", "Name7"];
$scope.friends = new Array();
$scope.friends.push(friends1);
$scope.friends.push(friends2);
//.......
$scope.index = 0; // in this example it can be 0 or 1
});
I want to achieve the following theoretical code:
VIEW.html
<li ng-repeat="player in players | filter:myCustomFilter(player)">{{player.name}}
CONTROLLER.js
// some theoretical conditional statement that return a boolean
$scope.otherCondition = true;
$scope.myCustomFilter = function(player) {
return player.name.substring(0,1).match(/A/gi) && $scope.otherCondition;
}
So I want all of my players to be loaded into an Angular model, but I only want to render players into the DOM whose names start with the letter 'A'. When I try and do something like this, my console informs me that player is undefined. Do I need to write a custom filter in order to achieve this (via angular.module().filter())?
Here's a working fiddle: http://jsfiddle.net/orlenko/jV6DK/
Html code (exactly as Karl Zilles suggested):
<div ng-app>
<div ng-controller="MyController">
<h2>Names starting with "A":</h2>
<ul>
<li ng-repeat="player in players | filter:myCustomFilter">{{player.name}}</li>
</ul>
<h2>All Names:</h2>
<ul>
<li ng-repeat="player in players">{{player.name}}</li>
</ul>
</div>
</div>
Javascript:
function MyController($scope) {
$scope.players = [{
name: 'Arthur'
}, {
name: 'William'
}, {
name: 'Bertha'
}, {
name: 'Alice'
}];
$scope.otherCondition = true;
$scope.myCustomFilter = function(player) {
return player.name.substring(0,1).match(/A/gi) && $scope.otherCondition;
}
}
Result
You don't need to pass player to the filter
<li ng-repeat="player in players | filter:myCustomFilter">{{player.name}}
Should work
The answers given are only partially correct, if you need to pass more arguments to the function you would need to create a closure and pass those arguments to the closure as follow:
The 'A' is passed to the closure and player is passed as a part of the context.
HTML:
<div ng-app>
<div ng-controller="MyController">
<h2>Names starting with "A":</h2>
<ul>
<li ng-repeat="player in players | filter:myCustomFilter('A')">{{player.name}}</li>
</ul>
<h2>All Names:</h2>
<ul>
<li ng-repeat="player in players">{{player.name}}</li>
</ul>
</div>
</div>
JS:
function MyController($scope) {
$scope.players = [{
name: 'Arthur'
}, {
name: 'William'
}, {
name: 'Bertha'
}, {
name: 'Alice'
}];
$scope.otherCondition = true;
$scope.myCustomFilter = function(letter) {
return function(player) {
var rgxp = new RegExp(letter, "g");
return player.name.substring(0, 1).match(rgxp) && $scope.otherCondition;
}
}
}
Checkout a working jsfiddle