ng-repeat called from controller function - javascript

I would like to write out list of some items in my app using ng-repeat but i faced with this problem:
Template
<ion-slide-box on-slide-changed="slideHasChanged($index)" ng-controller="AccountCtrl" ng-init="getData()">
<ion-slide ng-repeat="statitem in stats">
<div class="box vh80">
<h1>{{statitem.name}}</h1>
<h1>Test</h1>
</div>
</ion-slide>
</ion-slide-box>
And in AccountCtrl
angular.module('starter.controllers', [])
.controller('AccountCtrl', function($scope, Friends) {
$scope.getData = function() {
console.log('test');
var friends = [
{ id: 0, name: 'Scruff McGruff' },
{ id: 1, name: 'G.I. Joe' },
{ id: 2, name: 'Miss Frizzle' },
{ id: 3, name: 'Ash efe' }
];
$scope.stats = friends;
}
});
Problem is, that no item is obtained in template.
Where can be problem please?
Thanks for any help.
EDIT:
I solved it by moving the method calling to the parent div.
<ion-content class="padding" ng-controller="AccountCtrl" ng-init="getData()">

try to clear the template a little bit to test to be sure that your HTML is 100% right, so you may make such this:
<div ng-controller="AccountCtrl" ng-init="getData()">
<div ng-repeat="statitem in stats">
<h1>{{statitem.name}}</h1>
</div>
</div>
and if you see any results you have then you have to check your HTML and CSS template.

I solved it by moving the method calling to the parent div.
<ion-content class="padding" ng-controller="AccountCtrl" ng-init="getData()">

Related

Select DOM elements within template

There's this template that I call multiple times on the same page:
<div ng-controller="templateController">
<div class="source">
<div ng-repeat="item in info">
<div class="content" data-value="{{item.ID}}">{{item.name}}</div>
</div>
</div>
<br style="clear:both" />
<div class="receiver"></div>
</div>
and then I want to select all the elements with class="content" within each template scope in order to manipulate them.
How can I achieve this using JS?
EDIT :
Plunker
In this planker the console.log should print "1" twice and its printing "1" and then "2" when the template loads the second time
After more explanation here is a working example:
https://plnkr.co/edit/n5GOd6MDLyvG4ZAsuLvf?p=preview
The main idea is creating 2 lists and iterating over both and just moving data around between them on click.
angular.module("demo", []);
angular
.module("demo")
.controller("demoController", ["$scope", function($scope) {
}]);
angular
.module("demo")
.controller("templateController", ["$scope", "$timeout", function($scope, $timeout) {
$scope.sourceList = [
{
name: "john",
ID: 1
},
{
name: "Edward",
ID: 0
},
{
name: "Carl",
ID: 2
}
];
$scope.receiverList = [
{
name: "Bob",
ID: 1
}
];
$scope.moveToReceiver = function(item){
$scope.receiverList.push(item);
$.each($scope.sourceList, function(i){
if($scope.sourceList[i].name == item.name){
$scope.sourceList.splice(i, 1);
return false;
}
});
}
}]);
Most of the time you do not want to do DOM manipulation in Angularjs and instead hook into events with your controller. If you have to do DOM manipulation in AngularJS you would use directives
Docs on Creating a Directive that Manipulates the DOM
You could then use your link function to grab the children of your directive's element
function link(scope, element, attrs) {
var content = angular.element(element[0].querySelector('.content'));
}
https://stackoverflow.com/a/17329630/2033671

ng-repeat not working on a bootstrap row

Problem:
I am trying to repeat an array over a bootstrap row but the DOM is not repeating itself with any value.
My controller:
$scope.createSummary = function(){
$scope.entries = [];
for(var i=0;i<$scope.questions.length;i++){
$scope.entries.push({
question : $scope.questions[i].statement,
correct : $scope.questions[i].correct,
answered : $scope.answers[i]
});
}
console.log($scope.entries);
$state.go("home.summary");
}
My View:
<div class="container">
<div class="row">
<div class="col-sm-12" id="mast-head">
<h2>Match your answers against correct answers.</h2>
</div>
</div>
<div ng-repeat="entry in entries track by $index" class="row">
<div class="col-sm-9">
<p> {{$index+1}} <span ng-bind="entry.question"></span><p>
</div>
<div class="col-sm-1">
{{entry.correct}}
</div>
<div class="col-offset-1 col-sm-1">
{{entry.answered}}
</div>
</div>
</div>
Please note that this view is one of the many child states, and with this controller as a common controller.
What am I doing wrong here? Am I repeating over the wrong div?
You might should pass arguments to the state you are display and initialize the data in this views controller. I made an example using a service but its not exactly the same as what you will have. I think it might provide you with enough guidance to get your issue resolved. The ng-repeat should be fine once you get the data set correctly in the controller.
http://codepen.io/mkl/pen/ZKzMwe/
This is how I defined the service to be able to get and set the questions. I didn't add a set function for the answers but you should get the idea.
angular.module('app', [])
.service('service',
function() {
this.setQuestions = function(data) {
questions = data;
}
this.getQuestions = function() {
return questions;
}
this.getAnswers = function() {
return answers;
}
var questions = [{
'statement': 'A Statement 1',
'correct': false
}, {
'statement': 'A Statement 2',
'correct': false
}, {
'statement': 'A Statement 3',
'correct': false
}];
var answers = [
'Answer 1',
'Answer 2',
'Answer 3'
];
}
)

Unable to use inherited/isolated scope concept in my example plunker

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>

ng-repeat dynamic array name

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
});

Filter result set on $location.search() parameters AngularJS

How do I filter my result set on $location.search() parameters?
<div ng-repeat="tag in tags">
<div ng-class="{active:tagged(tag.id)}" ng-click="filter(tag.id)">
{{album.title}}
</div>
</div>
The class active appends if the result of tagged is true.
filter('tagged', function () {
return function (id) {
//Assume "tags" is also the name of the parameter.
//"tags" is being set by $location.search({tags:['123','456','789']});
return ($location.search().tags.indexOf(id) != -1)?true:false;
};
});
The convention inside ng-class is wrong but I'm using as an example to demonstrate knowledge gap.
I don't think you can use filter functions in ng-class expression, but you can simply define your tagged function inside the controller:
app.controller('AppController',
[
'$scope',
'$location',
function($scope, $location) {
$location.search('tags', [1, 3]);
$scope.tags = [
{id: 1, title: "Can't Hold Us"},
{id: 2, title: "Just Give Me A Reason"},
{id: 3, title: "Mirrors"},
{id: 4, title: "Get Lucky"},
];
$scope.tagged = function(id){
return $location.search().tags.indexOf(id) !== -1;
};
}
]
);
<body ng-controller="AppController">
<div ng-repeat="tag in tags">
<div ng-class="{active:tagged(tag.id)}">
{{tag.title}}
</div>
</div>
</body>
PLUNKER

Categories