Angular: View not updated inside ng-repeat - javascript

I am using a custom view directive inside a ng-repeat list like this:
//Directive
app.directive("card", function () {
return {
restrict: "E",
templateUrl: "views/card.html"
};
});
...
//List
<card ng-repeat="card in cards = main.data.getCards() | filter: sidebar.search() | orderBy: ['isPinned',$index]:true track by $index"
ng-if="content.checkCard(card)">
</card>
main.data is a reference to a service, where the data is being stored.
Here is a simplified version:
app.service('data', function ($http, engine) {
var cards = [];
...
return {
getCards: function () {
return cards;
},
setCards: function (data) {
cards = data;
engine.save("cards", cards);
},
When the data changes through the setCards() method, my list shows only empty elements. If I use the exact same html code inside my ng-repeat directly however, everything works fine. What can I do?

Related

In Angular 1.x how can I access controller methods from a custom directive?

I am currently trying to figure out the best way to access two controller methods from within my custom directive. My current code looks like so:
Parent Component Template (navMenus.html):
<menu-toggle section="navItem" ng-if="navItem.type === 'toggle'"></menu-toggle>
Parent Component Controller (navMenus.controller.js):
...
isOpen(section) {
return this.NavMenusFactory.isSectionSelected(section);
}
toggleOpen(section) {
this.NavMenusFactory.toggleSelectSection(section);
}
...
Directive Template (menuToggle.html):
<md-button class="md-button-toggle" ng-click="vm.toggle()">
{{ section.text | translate }}
</md-button>
<ul ng-show="vm.isOpen()" class="menu-toggle-list">
<li ng-repeat="subItem in section.subItems">
{{ subItem.text | translate }}
<menu-link section="subItem"></menu-link>
</li>
</ul>
Directive (menuToggle.directive.js):
...
return {
restrict: 'AE',
template,
replace: true,
scope: {
section: '=',
},
link(scope, element) {
$timeout(() => {
const $element = element;
scope.vm.toggle = function () {
console.log(scope.$parent.isOpen());
};
scope.isOpen = function () {
return $element.isOpen(scope.section);
};
scope.toggle = function () {
$element.toggleOpen(scope.section);
};
});
}
}
How can I access these methods?
Since there is scope in your directive, you have created an isolated scope.
So in order order to access the controller's function you can make use of events
Inside directive, create an $emit event, on the click event:
scope.toggle = function toggle (){
scope.$emit('EVENT_NAME', { data: true }) // here data is optional
}
In controller, you can perform action as:
$scope.$on('EVENT_NAME', function(event, data){
// here you can call the controller's method
})
This is the best way i know, to call a controller function from directive.
/* Directive template */
<md-button class="md-button-toggle" ng-click="vm.toggle()">
{{ section.text | translate }}
</md-button>
<ul ng-show="isOpen()" class="menu-toggle-list">
<li ng-repeat="subItem in section.subItems">
{{ subItem.text | translate }}
<menu-link section="subItem"></menu-link>
</li>
</ul>
/* Directive Code */
...
return {
restrict: 'AE',
template,
replace: true,
scope: {
section: '=',
isOpen: '&'
},
link(scope, element) {
$timeout(() => {
const $element = element;
scope.vm.toggle = function () {
console.log(scope.$parent.isOpen());
};
scope.isOpen = function () {
return $element.isOpen(scope.section);
};
scope.toggle = function () {
$element.toggleOpen(scope.section);
};
});
}
}
/* in your view, you can call controller fn */
<menu-toggle section="navItem" is-open="isOpen()" ng-if="navItem.type === 'toggle'"></menu-toggle>

Detail Page View not Showing Data in ionic

I'm new to Ionic. I write code for list. List is working perfectly but when click on any list-item it's not showing any data.
It showing me this error "Cannot GET /pilliondetails/1" how can i solve this?
app.factory('myService', function() {
var savedData = {}
function set(data) {
savedData = data;
console.log(savedData);
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
})
PillionList Controller:
.controller('PillionListCtrl',function($scope,$ionicHistory,myService){
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
$scope.pillions = [];
var promise=myService.get();
$scope.pillions=myService.get();
})
PillionDetail Controller:
.controller('PillionDetailCtrl',function($scope, $ionicHistory, $stateParams, myService)
{
$scope.myGoBack = function() {
$ionicHistory.goBack();
};
var promise=myService.get($stateParams.requestId);
console.log(promise);
})
PillionList.html :Showing list pf Pillions
<ion-list>
<ion-item data-ng-repeat="pillion in pillions">
<div class="list list-inset">
{{pillion.request_departure_date}}-{{pillion.request_departure_time}}
{{pillion.request_from}} >> {{pillion.request_to}}
{{pillion.user_first_name}} {{pillion.user_last_name}}
<a ui-sref="pilliondetails({pillionId:pillion.request_id})" nav-direction="enter">
<h2>More Details...</h2>
</a>
</div>
</ion-item>
</ion-list>
my app.js
.state('pillionlist', {
url: '/pillionlist',
templateUrl: 'templates/pillionlist.html',
controller: 'PillionListCtrl'
})
.state('pilliondetails', {
url: '/pillionlist/:pillionId',
templateUrl: 'templates/pilliondetails.html',
controller: 'PillionDetailCtrl'
})
Its redirecting to pillionDetail view but not showing data.
Please help.
The first thing i noticed is
ui-sref="pilliondetails({pillion.request_id})"
it should be key-value pair like this
ui-sref="pilliondetails({ your_id : pillion.request_id})"
and in stateProvider, the url of details page should contain parameter. for eg.
url : '/pilliondetails/:your_id'

Problems with ng-repeat, $scope, $http

im working with AnuglarJS 1.4.8. I want give out the data with ng-repeat.
I have the following problem and i have no more ideas to solve it. I tried the solutions from AnuglarJS but i doesnt work.
Could someone help me please.
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
http://errors.angularjs.org/1.4.8/$rootScope/infdig?p0=10&p1=%5B%5D
Service:
.service('database', function ($http) {
self = this;
this.url = 'http://localhost:3001';
this.getPersons = function(cb){
return $http({
method: 'GET',
url: self.url + '/loadperson'
}).success(function (data) {
cb(data);
});
};
});
Controller:
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.people = function(){
return{
getAll: function () {
database.getPersons(function (data) {
return data;
// should return a Object(id, name)
});
}
}
};
HTML:
<div ng-repeat="people in people().getAll()">
<p>{{people.name}}</p>
</div>
You are missing the non-blocking way of javascript. Try following, it should work
Controller:
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.loadPeoples = function(){
return{
getAll: function () {
database.getPersons(function (data) {
$scope.peoples = data;
// should return a Object(id, name)
});
}
}
};
$scope.loadPeoples();
})
HTML:
<div ng-repeat="people in peoples">
<p>{{people.name}}</p>
</div>
Try that.
Service:
.service('database', function ($http) {
self = this;
this.url = 'http://localhost:3001';
this.getPersons = function(){
return $http({
method: 'GET',
url: self.url + '/loadperson'
});
};
});
Controller:
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
database.getPerson().success(function(data) {
$scope.people = data;
});
});
HTML:
<div ng-repeat="person in people">
<p>{{person.name}}</p>
</div>
You should also be aware that you shouldn't return each time a NEW array for iterating. Otherwise angular will keep calling that function for retrieving a "stable" value for the array.
You've made a common error in javascript when running asynchronous queries. The pattern goes:
function outerFunction() {
invokeInnerFunction(function() {
return 3;
}
}
What does outerFunction() return? An error is to think it returns 3, but the answer is actually that outerFunction doesn't return anything.
Likewise, in your example getAll isn't actually returning anything; it's just calling an asynchronous method. This asynchronous method invoked $http, which triggers a digest loop which will result in getAll being called again, and so on for ever. Be thankful that angular can detect this problem.
You only want to call the database query once on startup, and initialize the list of people. Simply store this list in a variable so it won't query the database again on the next digest loop.
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.allPeople = [];
database.getPersons(function(data) {
$scope.allPeople = data;
});
};
An then for your HTML
<div ng-repeat="people in allPeople">
<p>{{people.name}}</p>
</div>
Much simpler.
Have you tried making a separate function to fetch the entities from the data base, then put this data in a variable, that you then will pass to the ngRepeat ?
your controller
angular.module('myApp')
.controller('personCtrl', function ($scope, database) {
$scope.people = [];
$scope.getPeople = function(){
return{
getAll: function () {
database.getPersons(function (data) {
$scope.people = data;
return;
// should return a Object(id, name)
});
}
}
//load the list of people
$scope.getPeople();
};
your view
<div ng-repeat="person in people">
<p>{{person.name}}</p>
</div>

ng-show - using a service as a scope parameter

I'm writing an angular 1.5.0-rc0 application using bootstrap for a nav bar component.
I want to show the user an added items to his navigation bar if his user group id is 1.
first I created a service:
app.factory('UserService', function() {
return {
userGroupId : null
};
});
I created the nav bar as a directive, so i included it in the main html file
<nav-bar></nav-bar>
and the nav-bar directive code:
(function () {
angular.module('myalcoholist').directive('navBar', function () {
return {
restrict: 'E',
templateUrl: 'views/nav.html',
controller: ['$scope','$auth', 'UserService',function ($scope,$auth,UserService) {
$scope.user=UserService;
$scope.isAuthenticated = function()
{
return $auth.isAuthenticated();
};
}]
}
});
})();
as you can see I set $scope.user as the returned object from UserService.
in my login controller, after a successful login I set the userGroupId.
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.userGroupId=data.data.user_group_id;
...
now.. my nav-bar template file is as the following code:
<li ng-show="user.userGroupId == 1">
Admin Drinks
</li>
even after the authentication, when I uset userGroupId to 1 the element is still not shown.
any ideas?
update
I debugged and noticed that UserService.userGroupId is still null. so
I changed the UserService to have the following code:
app.factory('UserService', function() {
var user = {userGroupId:null};
return {
setUserGroupId: function (userGroupId) {
user.userGroupId=setUserGroupId;
},
getUserGroupId: function () {
return user.userGroupId;
}
};
});
in my LoginController I now try to execute setUserGroupId:
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.setUserGroupId(data.data.user_group_id);
...
when I debug i see that userService is an object with two functions as I defined, but when the javascript chrome debugger tries to execute this line:
UserService.setUserGroupId(data.data.user_group_id);
I get the following error:
ReferenceError: setUserGroupId is not defined
at Object.setUserGroupId (app.js:21)
at login-controller.js:12
at angular.js:15287
at m.$eval (angular.js:16554)
at m.$digest (angular.js:16372)
at m.$apply (angular.js:16662)
at g (angular.js:11033)
at t (angular.js:11231)
at XMLHttpRequest.v.onload (angular.js:11172)
I have created a fiddle showcasing your requirement (as close as possible), and it seems to work fine.
http://jsfiddle.net/HB7LU/21493/
My guess is that you aren't actually setting the value when you think you are, and will likely require some debugging. Here is the code for brevity.
HTML
<div ng-controller="MyCtrl">
<div ng-click="clicked()">
Click ME, {{user.value}}!
</div>
<test-dir></test-dir>
</div>
JS
angular.module('myApp',[])
.service('TestService', function(){
return {
value: 2
};
})
.directive('testDir', function(){
return {
restrict: 'E',
template: '<div ng-show="user.value === 1">Here is some text</div><div>Some more always showing</div>',
controller: function ($scope, TestService) {
$scope.user = TestService;
}
};
})
.controller('MyCtrl', function($scope, TestService){
$scope.user = TestService;
$scope.clicked = function(){
TestService.value = 1;
};
});

$scope does not call inside function

Right now we are facing an issue in a controller that calls a DataService (Parse), the problem is that this code does not work:
function MainCtrl($scope, DataService, $location)
{
$scope.actionList = function() {
// Call the service and fetch the list of signatures that match the given action ID
DataService.getActions(function (results) {
$scope.$apply(function () {
// Apply the results to the signatureList model so it will refresh the table in the view
$scope.actionList = results;
});
});
};
}
I put a breakpoint in the DataService line but it doesn't get hit, but if I implement the Ctrl in this way it does get call and It works!!:
function MainCtrl($scope, DataService, $location)
{
// Call the service and fetch the list of signatures that match the given action ID
DataService.getActions(function (results) {
$scope.$apply(function () {
// Apply the results to the signatureList model so it will refresh the table in the view
$scope.actionList = results;
});
});
}
Any idea why is this happening??
Apart from that once is working (with the second implementation) I would like to show a property of the activity, if I try to get the property like this it does not work:
<div id="wrapper"><div id="scroller">
<div ng-controller="MainCtrl">
<ul id="thelist">
<li ng-repeat="action in actionList">{{action.get('Action')}}</li>
</ul>
</div>
</div></div>
But if I try to get the whole object like {{action}} I can actually see all the entries.
Change the controller to
function MainCtrl($scope, DataService, $location) {
$scope.getActionList = function() {
DataService.getActions(function(results) {
$scope.$apply(function() {
$scope.actionList = results;
});
});
};
$scope.getActionList();
}
Then if you want to reload actionList call getActionList()
Any idea why is this happening??
In your first example, you are simply defining a function named actionList on object $scope. Defining a function won't execute it (see #Arun's answer).
To show your data in the view, you can use normal JavaScript dot notation. If an action object looks like this:
{ prop1: 'property 1', prop2: [1, 2], prop3: { name: 'Javito'} }
You could write the view/HTML as follows:
<ul id="thelist">
<li ng-repeat="action in actionList">
prop1: {{action.prop1}}<br>
prop2: {{action.prop2[0]}} {{ action.prop2[1] }}<br> <!-- or use another ng-repeat here -->
prop3.name: {{action.prop3.name}}
</li>
</ul>

Categories