Angular Nested Controller in ng-repeat - javascript

I'm trying to use a nested controller in an ng-repeat so that the accordion panels on the page operate in different scopes (there may be a better way to do this). The problem is that the code in the nested controller never gets executed. I put a "debugger" stop point at the top and it never gets hit.
Here is my HTML:
<script src="~/Scripts/app/LWS/LWSCtrl.js"></script>
<script src="~/Scripts/app/LWS/lwsService.js"></script>
<script src="~/Scripts/app/Common/commonCtrl.js"></script>
<script src="~/Scripts/app/Common/commonService.js"></script>
<div ng-app-="myModule" ng-controller="LWSCtrl">
<div cg-busy="waitopr"></div>
<tabset>
<tab heading="Dashboard">
<div ng-repeat="m in majors">
<div ng-controller="commonCtrl">
<accordion close-others="oneAtATime">
<accordion-group is-open="status.open">
<accordion-heading>
<div style="height:20px">
<span class="pull-left">{{m.MajorName}}</span><i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-up': status.open, 'glyphicon-chevron-down': !status.open}"></i>
</div>
</accordion-heading>
...(shortened for brevity)
Here is the nested controller in its entirety:
angular.module('myModule').controller('commonCtrl', function ($scope, commonService, $, $timeout, $filter, $interval, $window) {
debugger;
$scope.oneAtATime = true;
$scope.status = {
isFirstOpen: false,
isFirstDisabled: false
};
getDashboard();
function getDashboard() {
$scope.waitopr = commonService.getlwsdashboard()
.success(function (data) {
$scope.dashboard = data;
var arr = {};
for (var i = 0, len = $scope.dashboard.length; i < len; i++) {
arr[$scope.dashboard[i]['CompanyID']] = $scope.dashboard[i];
};
$scope.majors = new Array();
for (var key in arr) {
$scope.majors.push(arr[key]);
}
angular.forEach($scope.majors, function (value, key) {
for (var i = 0; i < $scope.dashboard.length; i++) {
if (value.CompanyID == $scope.dashboard[i].CompanyID) {
$scope.majors[key].header = $scope.dashboard[i];
};
}
})
angular.forEach($scope.majors, function (value, key) {
$scope.waitopr = commonService.getlegend(value.CompanyID)
.success(function (data) {
$scope.majors[key].Legend = data;
for (var i = 0; i < $scope.dashboard.length; i++) {
if (value.CompanyID == $scope.dashboard[i].CompanyID) {
$scope.majors[key].MajorName = $scope.dashboard[i].MajorName;
};
}
});//end success
});//end forEach
angular.forEach($scope.majors, function (value, key) {
for (var i = 0; i < $scope.dashboard.length; i++) {
if (value.CompanyID == $scope.dashboard[i].CompanyID) {
items.push($scope.dashboard[i]);
};
}
$scope.majors[key].items = items;
items = [];
})
});//end success
};
})
I don't understand why the nested controller code is not executing. Any assistance is greatly appreciated!

Your controller is attached to an element within an ng-repeat. If the item you're repeating on is empty/undefined, your controller instance will never be invoked.
You must ensure that majors is populated and non-empty in the parent $scope.

Related

AngularJs - Execute Function in ng-repeat

My Web-App Should get images from server, show them and and give possibility to vote for Like it or Not.
Votes will be stored on DB.
my Controller :
$scope.beginSearch = function () {
$http
.get("http://example?q=" + $scope.search )
.then(function (response) {
$scope.url = response.data.data;
});
};
<tr ng-repeat="x in url">
<th>
<img src="{{x.images}}"></img>
<div class="well">
<i class="fa fa-thumbs-o-up fa-2x vertical-align" ng-click="vote_up(x.id)"></i>
<i class="fa fa-thumbs-o-down fa-2x vertical-align" ng-click="vote_down(x.id)" ></i>
</div>
</th>
</tr>
I was hoping to use a function in every ng-repeat, which would return
votes for like
{{ return_vote(x.id)}}
But it doesn't work, and as far I see, I should not use functions in html,
if they are not in ng-click functions.
ng-init also doesn't work.
Could anyone provide me help, how could I solve my problem?
Images are on some website, I just get them by using their WEB-API, so they doesn't have API for votes, I need to do it myself.
You can call your function inside brackets {{yourFunction(x.id)}} and add the logic to get the votes inside.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.url = [{
images: "http://lorempixel.com/g/100/100/",
id: 1
}, {
images: "http://lorempixel.com/100/100/",
id: 2
}]
$scope.getVotes = function(id){
//logic to get number of votes
return id * 5;
}
$scope.vote_up = function(id){
console.log("Vote up id " + id);
}
$scope.vote_down = function(id){
console.log("Vote down id " + id);
}
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="x in url">
<img src="{{x.images}}" />
<p>{{getVotes(x.id)}} votes</p>
<i class="fa fa-thumbs-o-up fa-2x vertical-align" ng-click="vote_up(x.id)"></i>
<i class="fa fa-thumbs-o-down fa-2x vertical-align" ng-click="vote_down(x.id)"></i>
</div>
</body>
Since you can't have the votes in the API you could alternatively create a service to get all the votes at once and then create some logic to match them to images.
e.g.
$scope.images = [];
var votes = [];
activate();
function activate() {
getImages().then(function () {
getVotes().then(function () {
matchVotesToImages();
//Now we have a property 'votes' in each image object which we can use in ng-repeat
});
});
}
function getVotes() {
var deferred = $q.defer();
$http.get('theUrl').then(success, fail);
function success(res) {
votes = res;
deferred.resolve();
}
function fail(res) {
console.log("Error");
console.log(res);
}
return deferred.promise;
}
function getImages() {
var deferred = $q.defer();
$http.get('theUrl').then(success, fail);
function success(res) {
$scope.images = res;
deferred.resolve();
}
function fail(res) {
console.log("Error");
console.log(res);
}
return deferred.promise;
}
function getIndex(array, property, valueToCompare) {
var i = 0;
var len = array.length;
for (i; i < len; i++) {
if (array[i][property] == valueToCompare) {
return i;
}
}
return -1;
}
function matchVotesToImages() {
var i = 0;
var len = $scope.images.length;
for (i; i < len; i++) {
//We pick need the votes of this specific image so
var indexAtVoteArray = getIndex(votes, 'id', $scope.images[i].id);
if (indexAtVoteArray != -1)
$scope.images.votes = votes[indexAtVoteArray];
else
$scope.images.votes = 0;
}
}
Thanks for answer.
$scope.vote_get = function (id) {
$http({
method: "GET",
url: "vote.php",
data: {
'id': id
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
.then(function (response) {
return response.data;
});
};
When I used this function to get votes, or return anything
, It does infinite loop.
Maybe I'am trying to do in wrong way, then please give me tips how to do that.
I'am just sure, that I need to send ID of image to .php file, this file will connect to database and return votes for provided ID.
Vote_up and Vote_down functions are same, they just POST data but seem to work ok.
Thanks
So, no one has idea :(?

AngularJs ng-repeat didn't updated after changing $scope variable

I have table with item list and modal window where i can change drug properties. When properties changed that drug have to remove from that list. But it's didn't remove.
Modal window:
$modal.open({
templateUrl:'app/interactions/partials/modals/resolveDrug.html',
controller: 'DrugsListController',
scope: $scope
}).result.then(function(data){
var index = _.findIndex($scope.drugs, {_id: data._id});
$scope.drugs.splice(index,1);
}
i think element didn't remove 'cause when i open modal window i create copy of my scope and then work with copy..
On that form i have refresh button that refresh all list.
$scope.refresh= function() {
$scope.drugs = UnresolvedDrugsService.query();
};
and it's didn't work too. I think it happens because i work with copy too.
Okey, i try to emit some event
$modal.open({
templateUrl:'app/interactions/partials/modals/resolveDrug.html',
controller: 'DrugsListController',
scope: $scope
}).result.then(function(data){
var index = _.findIndex($scope.drugs, {_id: data.data._id});
$rootScope.$emit('refreshDrug', index);
}
$rootScope.$on('refreshDrug', function(index){
$scope.drugs = [];
$scope.drugs.splice(index,1);
// $scope.drugs= UnresolvedDrugsService.query();
});
And it's not working.
Can you help me and describe what i doing wrong, thx!
UPD
modal window html
<form role="form" name="resolveDrugForm" ng-submit="saveResolvedDrug(drug) && $close(drug)">
........{some code, input's and label}......
<input type="submit" class="btn btn-primary" value="{{'COMMON.SAVE' | translate}}"/>
<button type="button" class="btn btn-default" ng-click="$dismiss()" >{{'COMMON.CANCEL' | translate}}</button>
code of ng-repeat
<tr ng-repeat="drug in drugs" ng-click="resolveDrug($index)">
<td>{{drug.productName || drug.description }}</td>
<td>{{drug.aiccode }}</td>
</tr>
and all method of controller:
$rootScope.$on('refreshDrug', function(index){
// $scope.drugs = [];
$scope.drugs.splice(index,1);
// $scope.drugs= UnresolvedDrugsService.query();
});
$scope.drugs= UnresolvedDrugsService.query();
$scope.refresh= function() {
$scope.drugs= UnresolvedDrugsService.query();
};
$scope.spliceEl = function(data){
var index = _.findIndex($scope.drugs, {_id: data._id});
$scope.drugs.splice(index,1);
return true;
};
$scope.saveResolvedDrug = function(drug){
DrugsService.addResolvedDrug(drug).then(function(data){
var index = _.findIndex($scope.drugs, {_id: data.data._id});
if(data.data.ingredients && data.data.ingredients.length > 0){
data.data.ingredients = JSON.parse(data.data.ingredients);
}
$scope.drugs.splice(index,1);
return true;
});
return true;
};
$scope.resolveDrug=function(index){
$scope.drug={};
var drugs = $scope.drugs;
$scope.drug=angular.copy($scope.drugs[index]);
var scope=$scope;
$modal.open({
templateUrl:'app/interactions/partials/modals/resolveDrug.html',
controller: 'DrugsListController',
scope: $scope
}).result.then(function(data){
console.log($scope.drugs);
var index = _.findIndex($scope.drugs, {_id: data._id});
//$scope.drugs.splice(index,1);
console.log($scope.drugs);
$rootScope.$emit('refreshDrug', index);
}, function(data){
}).finally(function(data){
$scope.refresh();
});
}
I didn't know why it didn't works with events. But if saveDrug in modal result but sumbit form - work fine.
Now code looks like
$scope.resolveDrug=function(index){
$scope.drug={};
var drugs = $scope.drugs;
$scope.drug=angular.copy($scope.drugs[index]);
var scope=$scope;
$modal.open({
templateUrl:'app/interactions/partials/modals/resolveDrug.html',
controller: 'DrugsListController',
scope: scope,
resolve: {
drug: function () {
return $scope.drug;
}
}
}).result.then(function(data){
}, function(data){
}).finally(function(data){
});
}
$scope.saveResolvedDrug = function(drug){
DrugsService.addResolvedDrug(drug).then(function(data){
var index = _.findIndex($scope.drugs, {_id: data.data._id});
if(data.data.ingredients && data.data.ingredients.length > 0){
data.data.ingredients = JSON.parse(data.data.ingredients);
}
$scope.drugs.splice(index,1);
return true;
});
return true;
};

How to pass AngularJS expressions to controller

I want to pass AngularJS Expression value to the controller.
HTML code :
<div data-ng-controller="AlbumCtrl">
<div data-ng-repeat="z in songInfo">
<div data-ng-repeat="b in z.album">
{{b.tracks}}
</div>
</div>
<!-- Pagination -->
<div class="pageing">
<a class="prev" data-ng-disabled="currentPage == 0" data-ng-click="currentPage=currentPage-1">prev</a>
<a class="pageingg" href="#/song">{{currentPage+1}}/{{numberOfPages()}}</a>
<a class="next" data-ng-disabled="currentPage >= data.length/pageSize - 1" data-ng-click="currentPage=currentPage+1">next</a>
</div>
</div>
Here {{b.tracks}} is the count of total number of tracks in the album. I have to pass this data to the controller AlbumCtrl.
Controller :
.controller('AlbumCtrl', function($scope, $routeParams, $http) {
$scope.album_id = $routeParams.albumId;
$http.post('api-call.php', { albumid: $scope.album_id, evt: 13 }).success(function(data) {
$scope.songInfo = data;
});
//Pagination
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.data = [];
$scope.numberOfPages=function(){
return Math.ceil($scope.data.length/$scope.pageSize);
};
for (var i=0; i<AngularJS expression value; i++) {
$scope.data.push("Item "+i);
}
});
Here, in controller AngularJS expression value is the value we have to get here.
if it have only one value. then you can easily get the values from controller, you don't need to pass it.
try this way $scope.songInfo[0].album[0].tracks
Something like
for (var i=0; i< $scope.songInfo[0].album[0].tracks; i++) {
$scope.data.push("Item "+i);
}
Try this two line,
var obj = JSON.parse($scope.songInfo);
var track = obj.root.tracks[0];

AngularJS directive templates ng-repeat funny substitution

I'm struggling with angularjs directive templates. The {{variable}} works in a very strange way inside a ng-repeat,
<div ng-controller="MyCtrl">
<h2>here i am</h2>
<button type="button" ng-click="addItem()" class="btn btn-primary">Howdy</button>
<div ng-repeat="item in items track by $index" itemlist></div>
</div>
<script type="text/ng-template" id="template.html">
<div>
Howdy {{item.itemNum}} {{item.name}}
</div>
</script>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope) {
$scope.count = 0;
$scope.items = [];
var newItem = {
itemNum: 0,
name: "New"
};
$scope.addItem = function () {
newItem.itemNum = $scope.count;
console.log('adding item ' + newItem.itemNum);
$scope.items.push(newItem);
$scope.count += 1;
};
});
myApp.directive('itemlist', function ($compile) {
return {
templateUrl: 'template.html',
};
});
I have created a jsfiddle showing my problem here: http://jsfiddle.net/dk253/8jm5tjvf/23/.
What am I missing or doing wrong?
Thanks!
The reason is you are updating the property on the same object reference (newItem) every time. So it updates all other items in the array because they all just point to the same object or in other words they are all same. You could instead get the copy of the object using angular.copy and push that item.
var item = {
itemNum: 0,
name: "New"
};
$scope.addItem = function () {
var newItem = angular.copy(item); //Get the copy
newItem.itemNum = $scope.count;
Fiddle

AngularJS: Hitting a strange issue with $scope variables

In the following code, whenever you delete an item from the delete link in the list, it will only delete the item from the list, but it will not delete the currently selected item. (The item displaying once you click on it). However, if you click on the delete link next to the currently selected item, it will delete from both places.
To replicate what I'm seeing:
Add a bunch of items by typing in the text box and hitting enter a few times.
Select one of the items from the list.
Click delete next to the item when it displays below.
This is the correct behavior.
Select another item you created earlier.
Now click the delete link next to the item in the list.
The item is removed from the list, but not the currently displayed item.
When I step into the code $scope.currentUser is undefined when I click on the delete link in the list.
Why is this happening?
<html ng-app="myApp">
<head>
<script src="http://code.angularjs.org/1.0.1/angular-1.0.1.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.config(function($routeProvider) {
$routeProvider.when('/User/:id', {
controller: UserCtrl,
template: '<h1>{{currentUser.name}}</h1> <a ng-click="deleteUser(currentUser.id)">delete me</a>'
});
});
app.factory('userSvc', function(){
return new UserService();
});
function UserCtrl($scope, $routeParams, $location, userSvc) {
var currUser = userSvc.getUser($routeParams.id);
$scope.currentUser = currUser;
$scope.users = userSvc.getAllUsers();
$scope.addUser = function () {
var user = {
id: userSvc.nextId(),
name: $scope.addUserName
};
userSvc.addUser(user);
$scope.addUserName = '';
$location.url('/User/' + user.id);
};
$scope.deleteUser = function(id) {
if($scope.currentUser != null && $scope.currentUser.id == id) {
$scope.currentUser = null;
}
userSvc.delete(id);
};
};
function UserService() {
var users = [{id: 1, name: 'Ben' }];
this.delete = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
users.splice(i,1);
}
}
};
this.addUser = function(user) {
users.push(user);
};
this.getAllUsers = function() {
return users;
};
this.getUser = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
return user;
}
}
};
this.nextId = function() {
var maxId = 0;
for(var i = 0; i < users.length; i++) {
var user = users[i];
maxId = Math.max(maxId, user.id);
};
return maxId + 1;
};
}
</script>
</head>
<body>
<div ng-controller="UserCtrl">
<form ng-submit="addUser()">
<input ng-model="addUserName" type="text"/>
<input type="submit" value="Add"/>
</form>
<ul>
<li ng-repeat="user in users">{{user.name}} <a ng-click="deleteUser(user.id)">delete</a></li>
</ul>
</div>
<div ng-view></div>
</body>
</html>
It turns out that selecting a user from the list actually also created a brand new scope that was seperate from the one used to bind the list.
Thanks to Gloopy's comment above to check out Batarang, I was able to see this happen. If this happens to help you, please +1 his comment.
According to the documentation on Scopes some directives will actually cause a new scope to be created. I'm assuming that clicking a link that is being handled by the $routeProvider also results in the creation of a whole new scope tree, likely because it's creating another instance of that controllor.

Categories

Resources