ng-include with template does not render data - javascript

I have two java script - one for controller and one for data service call.
On index page, I try to load tab with data from database returned results. It throws undefined for scope data which I can see already set but it seems html renders before that
Index page
<li ng-repeat="(Id, Name) in data.list" ng-class="{active: isSel(Id)}">
<a ng-click="isChange(Id, Name);" ng-href="#{{Name}}" role="pill" data-placement="right" data-toggle="tab">
{{Name}}
</a>
</li>
<div class="tab-content">
<div ng-repeat="(Id, Name) in data.list" class="tab-pane template fade in" id="{{Name}}" ng-class="{active: isSel(Id)}">
<div class="row" ng-include="'templates/my_widget.html'" > </div>
</div>
</div>
my_widget.html
<div class="col-md-4 component list-widget" ng-repeat="(Id, Name) in data.LatestBList">......blah blah....</div>
Controller
$scope.isSelected = function(entry) {
return $scope.tab === entry;
};
$scope.isChange = function(Id, Name) {
$scope.tab = Id;
$scope.Name = Name;
$scope.data.LatestBList= [];
$scope.data.LatestBList= ds.getList($scope.Name); // database retuned list
};
I get the error like
Error: [ngRepeat:dupes] http://errors.angularjs.org/1.4.3/ngRepeat/dupes?p0=(Id%2C%20Name)%20in%20data.LatestBList&p1=undefined%3Aundefined&p2=undefined
at Error (<anonymous>
Any suggestion ?

ng-include gets created with its own scope hence it was returning undefined. $parent can be used to obtain the parent scope which solved the issue.

Related

Losing scope when using ng-include for recursion ( Updating object at run time, not reflecting the changes on child template) in angularjs

I'm using ng-include for recursion. it's loading correct at first time but when I change anything in the object at run time, it doesn't reflect the changes on html. ng-include will create a child scope for that, so its not getting changes from parent scope. How can I bind the scope or reflect the changes in the html? Below is the code snippet for main.html
<div ng-switch on="value.length>0">
<div ng-switch-when="true">
<div ng-init="item = value[0];" ng-include="'test/views/partialTemp.html'">
</div>
</div>
</div>
In Partial Template
<div class="row" ng-repeat="(key, result) in item" ng-if="item ">
.......
<div ng-switch on="result.length > 0 ">
<div ng-repeat="tempValue in result">
<div ng-switch-when="true">
<div ng-init="item = tempValue;" ng-include="'test/views/partialTemp.html'"></div>
</div>
</div>
</div>
....
</div>
In JS File
onRadioButtonChange = function(key, value, item) {
var self = this;
self.serviceObj.Response.values = self.updateServiceObject(self.serviceObj.Response.values, key, value, false); // Updating the actual object which came from service
self.objectToShow = JSON.parse(JSON.stringify(self.serviceObj)); // Taking the actual object which will show in the HTML
self.objectToShow.Response.values = self.filterObjectToShow(self.objectToShow.Response.values); // it'll add/remove the child radio button
}
objectToShow is the object which I'm using to render the html

Angularjs nested controller called just one time

I'm new in Angularjs and I have an app, with some "projects", which have a local menu displayed on some pages. Index.html contains the main navbar with footer :
<body ng-app="ysi-app" ng-controller="MainController">
<div class="page-content">
<div class="row">
<div class="col-md-2">
<div class="sidebar content-box" style="display: block;">
<ul class="nav">
<!-- Main menu -->
<li ng-if="isAuthenticated()">{{name}}</li>
<li class="current">Dashboard</li>
<li>Projects</li>
</ul>
</div>
<div ng-if="isAuthenticated() && displayProjectMenu == true" ng-include="'views/localMenu.html'" ng-controller="LocalMenuController">
</div>
</div>
<div ng-view></div>
</div>
So I have a nested controller LocalMenuController for the local menu and a main controller. The project controller sets the datas :
angular.module('ProjectCtrl',[]).controller('ProjectController',function($scope,$location, ProjectService,$route, AuthenticationService, $rootScope){
$scope.setProjectDatas = function(projectName, projectId){
ProjectService.setName(projectName);
$rootScope.projectId = projectId;
};});
I set the id of one project to the $rootScope for testing (I have a Service which will do that better) and get it in the LocalMenuController :
angular.module('LocalMenuCtrl',[]).controller('LocalMenuController', function($scope, ProjectService, $rootScope) {
$scope.projectId = '';
$scope.projectId = $rootScope.projectId;
});
I display projects in a table and when I clicked on one of it, the function setProjectDatas(name,id) is called. The problem is when I clicked on one project, the id of the project is correct and set but when I go previous and clicked on another project, the id is the old id of the project previously clicked. The datas are not updating. I googled my problem but found nothing on it.
I think the LocalMenuController is called only one time but not after.
What am I doing wrong ?
Thank you
UPDATE
I've created a Directive which displays the template but it's still not updating the partial view localMenu.
LocalMenu Directive :
angular.module('LocalMenuCtrl',[]).controller('LocalMenuController', function($scope, ProjectService, $rootScope) {
console.log('-> LocalMenu controller');
})
.directive('localMenu', function($rootScope){
return {
templateUrl: '/YSI-Dev/public/views/partials/localMenu.html',
link: function(scope){
scope.projectId = $rootScope.projectId;
}
};
});
A part of index.html
<div ng-if="isAuthenticated() && displayProjectMenu == true" ng-controller="LocalMenuController">
<div local-menu></div>
</div>
Partial view localMenu :
<div class="sidebar content-box" style="display: block;">
<ul class="nav">
<li><i class="glyphicon glyphicon-list-alt"></i> Backlog</li>
<li><i class="glyphicon glyphicon-user"></i> My team </li>
</ul>
</div>
I'm trying to get the projectId from the $rootScope and inject it in the <a href="#/project/{{projectId}}" but I have some troubles. What's the way to do that ?
First of all, try using directives instead of ng-controller. You can encapsulate your code and template into a unit. You can also try creating a component. Pass some data to the directive/component and Angular will take care of updating the template and running whatever needs to run within the directive/component. (Given that you used two-way data-bindings)
From the code above, I cannot see what would trigger LocalMenuController to run again.

AngularJS ng-if inside ng-repeat does not work

Here is my code:
<body ng-controller="QueryCntl">
<div>
<h1> Target:{{target}}</h1>
</div>
<div ng-app="myApp" ng-controller="mytableCtrl">
<div ng-include="'header.html'"></div>
<div id="menuList">
<ul class="menuNav">
<li class="menuList_Slide" ng-repeat="x in names">
<div>
{{ x.category }}
</div>
<div ng-if="{{target}} == {{x.id}}"> //Display subcategory if true
<ul id="subCategories">
<li>
Childid should be displayed
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
<script>
var app = angular.module('myApp', [], function($locationProvider) {
$locationProvider.html5Mode(true);
});
function QueryCntl($scope, $location) {
$scope.target = $location.search()["categoryid"];
}
app.controller('mytableCtrl', function($scope, $http) {
$http.get("api/topCategories")
.success(function(response) {$scope.names = response;});
});
</script>
I want to display only 1 subcategory if {{target}} is equal to {{x.id}}. But for now it prints everything... {{target}} gets value from the url where ?categoryid=some_number and x.id is a value from DB. These values works fine in my code.
I would appreciate any help.
EDIT: ng-if="target == x.id" does not help.
ngIf doesn't need to use {{}} - it's already an Angular expression:
div ng-if="target == x.id"
Problem solver:
I inserted
<base href="category.html">
in head tags and deleted bad script source.
You don't need to interpolate properties within the ng-if directive's conditional as Angular evaluates the complete expression against the scope already. Try this:
ng-if="target == x.id"
Replace:
<div ng-if="{{target}} == {{x.id}}">
With:
<div ng-if="target == x.id">
The ng-if attribute should contain plain JavaScript, instead of those interpolation tags ({{}}).
This holds true for all ng- attributes.
ngIf directive expects an expression, so you don't need interpolation tags:
<div ng-if="target == x.id"> //Display subcategory if true
<ul id="subCategories">
<li>
Childid should be displayed
</li>
</ul>
</div>
And one more thing: you are not initializing $scope.target because corresponding controller is outside of the ng-app. Remove ng-controller="QueryCntl" and add target initialization into mytabeCtrl:
app.controller('mytableCtrl', function($scope, $http) {
$scope.target = $location.search()["categoryid"];
$http.get("api/topCategories")
.success(function(response) {$scope.names = response;});
});

Access a ng-repeat scope from a controller

I'm trying to display some comment with two nested ng-repeat:
<div ng-repeat="element in elements" >
<ul>
<!-- comments -->
<li ng-repeat="comment in comments">
<span>Comment</span> <strong>{{comment.username}}</strong>
<blockquote>{{comment.content}}</blockquote>
</li>
</ul>
</div>
Here's what's in the controller:
$scope.comments = [];
$scope.populateComments = function(content_id){
ProjectsService.commentsQuery(content_id)
.then(function (data) {
$scope.comments = data;
})
}
$scope.populateComments(element.id);
Obviously it's not working, my problem is that I don't know how, nor if it's possible, to access the property of an object of the ng-repeat scope (to get element.id and get only the comments related to the element involved).
Any ideas?
Thank you in advance!
You can access the property of an object of the ng-repeat scope. You need to re-factor your code.
In Html
<div ng-repeat="element in elements" >
<ul>
<!-- comments -->
<li ng-repeat="comment in element.comments">
<span>Comment</span> <strong>{{comment.username}}</strong>
<blockquote>{{comment.content}}</blockquote>
</li>
</ul>
</div>
In JS
$scope.populateComments = function(element){
ProjectsService.commentsQuery(element.id)
.then(function (data) {
element.comments = data;
})
}
$scope.populateComments(element);

AngularJS update model on click of element and also toggle CSS class

New to Angular and a bit confused. I have a list item that needs to display a tick or a cross depending on an initial value from its controller.
When a user clicks the list item I want to change the value to its current opposite and then update the CSS class to reflect this in the DOM.
Currently I have the following controller:
app.controller('SetupSettingsCtrl', ['$scope', '$rootScope', '$location', function ($scope, $rootScope, $location) {
console.log('setup controller loaded');
$scope.data ={
about: {
uie: '439213949123I034',
appVersion: '3.23453'
},
lab: {
sleep: false,
move: true
},
stats: {
optOut: true
}
};
$scope.chkItem = function($event, prop){
console.log(prop);
};
}]);
And the following template partial:
<div class="pure-u-1">
<h1 class="h2 text-center">About</h1>
<p class="text-center">Phone UIE: <span class="text-valid">{{uie}}</span></p>
<p class="text-center">App version: <span class="text-valid">{{appV}}</span></p>
<p class="text-center"><i class="icon-refresh"></i> Manual Update</p>
</div>
<div class="pure-u-1">
<h2 class="text-center">LAB functions</h2>
<section class="view-content">
<ul class="center-block list-bare list-icon-box-chk">
<li class="pointer" ng-class="{'un-chk': !sleep}" ng-model="sleep" ng-click="chkItem($event)">Sleep with phone on bed</li>
<li class="pointer" ng-class="{'un-chk': !move}" ng-model="move" ng-click="chkItem($event)">Movement checker</li>
</ul>
</section>
</div>
<div class="pure-u-1">
<h2 class="text-center">Anonymous Statistics</h2>
<section class="view-content">
<ul class="center-block list-bare list-icon-box-chk">
<li class="pointer" ng-class="{'un-chk': !optOut}" ng-model="optOut" ng-click="chkItem($event)">I do not want anonymous statistics to be geathered for Health research, and healthcare improvement</li>
</ul>
</section>
</div>
I do not now how to pass the model reference to update the $scope value to trigger the change? When I pass the model property reference I get the value.
I need to call the controller method to pass the model value to the server also.
You should do both: toggle the model as well as call the function inside ng-click without the need of passing the model as a parameter. Also you dont need to bind the model to the lis:
<li class="pointer"
ng-class="{'un-chk': !data.lab.sleep, 'chk': data.lab.sleep}"
ng-click="data.lab.sleep = !data.lab.sleep; chkItem($event)">
Sleep with phone on bed
</li>
<li class="pointer"
ng-class="{'un-chk': !data.lab.move, 'chk': data.lab.move}"
ng-click="data.lab.move = !data.lab.move; chkItem($event)">
Movement checker
</li>
(I guess those {{uie}} and {{appV}} in your HTML need to be like {{data.about.uie}} and {{data.about.appVersion}})
JS:
$scope.chkItem = function($event){
/* do something here */
};
In your "Controller" it will be avaliable
$scope.chkItem = function($event, prop){
console.log(data.lab.sleep);
};
You can update directly no need to pass
<li class="pointer" ng-class="{'un-chk': !data.lab.sleep}" ng-model="data.lab.sleep" ng-click="chkItem($event)">Sleep with phone on bed</li>

Categories