AngularJS: Unable to reload/refresh view from controller - angularjs

How do i refresh angularjs view from controller once the array/list is updated?
Following is my code:
<div class="main-page" ng-app="GoalsListing1">
<div ng-controller="CategoriesController as catCtrl">
<ul class="side-nav">
<li ng-class="{active: $index == catCtrl.selected}" ng-click="catCtrl.setSelected($index)" ng-repeat="cat in catCtrl.categories">
<span class="span-text">{{cat.name}}</span>
</li>
</ul>
</div>
<div id="contentsGrid">
<table ng-controller="DetailsController as detailsCtrl">
<thead>
<tr><th>Goal Name</th></tr>
</thead>
<tbody>
<tr ng-show="detailsCtrl.goalDetailsList === undefined">
<td align="center">No data found to display</td>
</tr>
<tr ng-repeat="detail in detailsCtrl.goalDetailsList">
<td>{{detail}}</td>
</tr>
</tbody>
</table>
</div>
</div>
and JS:
var app = angular.module("GoalsListing1", []);
//categories at top rendering
var goalCategories = [{"id":"1", "name":"Cat1"}, {"id":"2", "name":"Cat2"}];
//against each category its details
var goalDetails = {"Cat1":["goal1", "goal2"], "Cat2":["goal1", "goal2", "goal3"]};
//service to share data between controllers
app.service("GoalDetailService", function($rootScope){
this.goalDetail = goalDetails;
this.selectedCatName = "";
this.filteredList = {};
this.getGoalDetail = function(catName){
this.filteredList = this.goalDetail[catName];
return this.filteredList;
};
this.setGoalDetail = function(catName){
this.filteredList = this.goalDetail[catName];
};
});
//rendering side nav goal categories and set selected category
app.controller("CategoriesController", function($scope, GoalDetailService){
this.categories = goalCategories;
this.selected = 0;
GoalDetailService.selectedCatName = this.categories[this.selected].name;
GoalDetailService.setGoalDetail(GoalDetailService.selectedCatName);
this.setSelected = function(index){
this.selected = index;
GoalDetailService.selectedCatName = this.categories[this.selected].name;
GoalDetailService.setGoalDetail(GoalDetailService.selectedCatName);
};
});
//details grid rendering controller
app.controller("DetailsController", function($scope, GoalDetailService){
$scope.service = GoalDetailService;
this.goalDetailsList = GoalDetailService.filteredList;
//set watch when selection from side nav changes
$scope.$watch('service.filteredList', function(newList){
$scope.goalDetailsList = newList;
});
});
Here is the fiddle:
http://jsfiddle.net/5fnp8tgs/
When I switch between Cat1 and Cat2 the corresponding array from goalDetails list doesn't updated in View.
Please help me.

While the other answer solves the issue, the alias isn't a problem... you're just not using it correctly. You need to use this instead of $scope.
app.controller("DetailsController", function($scope, GoalDetailService){
var self = this;
$scope.service = GoalDetailService;
this.goalDetailsList = GoalDetailService.filteredList;
//set watch when selection from side nav changes
$scope.$watch('service.filteredList', function(newList){
self.goalDetailsList = newList;
});
});
updated jsfiddle

You don't need the controller here: <tr ng-repeat="detail in detailsCtrl.goalDetailsList">
Instead use this:
<tr ng-repeat="detail in goalDetailsList">
It uses the goalDetailsList from the controller's $scope, which you already declared here:
<table ng-controller="DetailsController as detailsCtrl">

Related

Count clicks and add to input

First of all I am very new in Angular JS.
I have a list of items and by clicking on each one, it should be added to the table. The items are stored in a json file.
If the click event repeated several times the counter input which is located on the table must increases.
<ul class="list-inline" >
<li ng-repeat="food in foods" class="food_list">
<img class="img-box" src="images/{{ food.food_photo }}" ng-click = 'addRow(food)'><br/><span>{{food.food_name}}</span>
</li>
</ul>
<table class="table" id="table-right">
<tr>
<th>Item Name</th>
<th>Quantity</th>
<th>Price</th>
<th class="hidden-print">Delete</th>
</tr>
<tr ng-repeat="row in rows">
<td>{{row.food_name}}</td>
<td><input type="number" class="form-control" ng-model="row.food_count"></td>
<td>{{row.food_cost}}</td>
<td class="hidden-print"><button class="btn btn-info hidden-print" data-ng-click="removeRow($index)">Remove</button></td>
</tr>
app = angular.module('app',[]);
app.controller('MyCtrl', ['$scope','$http', function($scope, $http){
$scope.rows = [];
$scope.addRow = function(obj) {
$scope.foodname = obj.id;
$scope.foodprice = obj.price;
$scope.rows.push(obj);
$scope.counter++;
}
}]);
Could you please help me? Thank You.
First you have to understand that food_count property of a row object is the variable that should be updated on repetitive clicks. Updating any other $scope variables won't change row specific data because your view is bound to $scope.rows object.
Your addRow function should look like this.
$scope.addRow = function(obj) {
if($scope.rows.indexOf(obj) >= 0){ // if this obj already exist
$scope.rows[$scope.rows.indexOf(obj)].food_count++;
}
else
$scope.rows.push(obj);
}
Then the objects of $scope.foods should have a property called food_count to display.
$scope.foods = [
{food_name:'Jani',food_cost:'10', food_count:0},
{food_name:'Hege',food_cost:'8',food_count:0},
{food_name:'Kai',food_cost:'5',food_count:0}]
solution

Issues converting "controller as" syntax to classic $scope

I have had major issues trying to convert my code from "controller as/this" syntax to classic $scope syntax, without breaking the code. I tried simply replacing "this" with $scope and removing the "controller as" assignments for both controllers, with no luck. I have created a jsfiddle for this with the controller as/this syntax so you can see how it should be working correctly prior to converting the syntax to $scope. https://jsfiddle.net/6zk9vujo/6/
This is another jsfiffle showing the broken code, when I simply replace _this with $scope and remove the controller as assignments in the html https://jsfiddle.net/6zk9vujo/12/ Thank you for your help in advance.
HTML
<div ng-app="app">
<div ng-controller="mainController as main">
<h2>
Main Controller
</h2>
<div>
<table>
<tr>
<td>Item</td>
<td>Price</td>
<td>Quantity</td>
<td></td>
</tr>
<tr ng-repeat="product in main.items">
<td>{{product.name}}</td>
<td>{{product.price | currency}}</td>
<td>
<button ng-click="main.increaseItemAmount(product)">
+
</button>
{{product.quantity}}
<button ng-click="main.decreaseItemAmount(product)">
-
</button>
<button ng-click="main.addToCart(product)">
Add to Cart
</button>
</td>
</tr>
</table>
</div>
</div>
<div ng-controller="cartController as cart">
<h2>
Cart Controller
</h2>
<div>
<table>
<tr>
<td>Item</td>
<td>Price</td>
<td>Quantity</td>
<td></td>
</tr>
<tr ng-repeat="product in cart.cartStorage.items">
<td>{{product.name}}</td>
<td>{{product.price | currency}}</td>
<td>
<button ng-click="cart.increaseItemAmount(product)">
+
</button>
{{product.quantity}}
<button ng-click="cart.decreaseItemAmount(product)">
-
</button>
<button ng-click="cart.removeFromCart(product)">
Remove from Cart
</button>
</td>
</tr>
</table>
</div>
</div>
</div>
JAVASCRIPT
angular.module('app', [])
.factory('cartStorage', function() {
var _cart = {
items: []
};
var service = {
get cartItems() {
return _cart;
}
}
return service;
})
.controller('mainController', function(cartStorage) {
var _this = this;
_this.cartStorage = cartStorage.cartItems;
_this.items = [{
name: 'Apple',
price: 2.5,
quantity: 1
}];
_this.addToCart = function(product) {
_this.cartStorage.items.push(product);
product.addedToCart = true;
}
_this.increaseItemAmount = function(product) {
product.quantity++;
product.showAddToCart = true;
}
_this.decreaseItemAmount = function(item) {
product.quantity--;
if (product.quantity <= 0) {
product.quantity = 0;
product.addedToCart = false;
product.showAddToCart = false;
var itemIndex = _this.cartStorage.items.indexOf(product);
if (productIndex > -1) {
_this.cartStorage.items.splice(productIndex, 1);
}
} else {
product.showAddToCart = true;
}
}
})
.controller('cartController', function(cartStorage) {
var _this = this;
_this.cartStorage = cartStorage.cartItems;
_this.increaseItemAmount = function(item) {
product.quantity++;
}
_this.decreaseItemAmount = function(item) {
item.quantity--;
if (item.quantity <= 0) {
item.quantity = 0;
item.addedToCart = false;
item.showAddToCart = false;
var productIndex = _this.cartStorage.items.indexOf(item);
if (productIndex > -1) {
_this.cartStorage.items.splice(productIndex, 1);
}
}
}
_this.removeFromCart = function(item) {
item.quantity = 0;
item.addedToCart = false;
item.showAddToCart = false;
var productIndex = _this.cartStorage.items.productOf(item);
if (productIndex > -1) {
_this.cartStorage.items.splice(productIndex, 1);
}
}
});
In the template, remove all main. and cart. and change to ng-controller="mainController" and ng-controller="cartController".
In your controllers, inject $scope and assign it to _this for easiest migration.
.controller('mainController', function($scope, cartStorage) {
var _this = $scope;
and
.controller('cartController', function($scope, cartStorage) {
var _this = $scope;
https://jsfiddle.net/6zk9vujo/10/
Alternatively, just replace all _this references with $scope in your controllers.
You also have a bunch of mixed up product / item and productIndex / itemIndex variables. I've standardised them all in this fiddle as well as fixed the logic around re-adding the same product.
https://jsfiddle.net/6zk9vujo/13/
It will work if you remove the "as" syntax when you define the controller in the view: ng-controller="mainController" and ng-controller="cartController".
Edited: I made a mistake of putting the wrong fiddle link.
https://jsfiddle.net/analiza641/jr0stbLq/3/

How to go from one <a> to another <a> in angularJs

CONTROLLER
$scope.employee = {};
$scope.setEmployee = function (employee) {
$scope.employeeId = employee.id;
$scope.employee = employee;
a($scope.employeeId);
};
var a = function () {
$scope.meetingTypes = MeetingService.findByEmployee({
'employeeId': $scope.employeeId
}, function () {
angular.forEach($scope.meetingTypes, function (meetingType) {
$scope.meetings = MeetingService.findByMeetingType(meetingType);
});
});
};
TEMPLATE
<tr>
<td>
<a ng-repeat="meetingType in meetingTypes">
- {{meetingType}}
</a>
<a ng-repeat="meeting in meetings">
- {{meeting}}
</a>
</td>
</tr>
Here I want to open second <a> tag on click of first <a> tag
The view should like tree view
LIKE :
- meeting_type
- meeting 1
- meeting 2
all services are declared in my .factory
Here I am getting meeting Type properly but i want to open list of meetings on click of meetingType <a> tag but i am not getting meetings here,
Is ng-href is helpfull here ?
Here is a some sample code which I think demonstrates what you want to acheive -
<table ng-app="myApp" ng-controller="TestCtrl">
<tr>
<td>Get Meetings</td>
</tr>
<tr>
<td>
<ul>
<li ng-repeat="meetingType in meetingTypes track by $index">
- {{meetingType.typeName}}
<ul ng-show="showMeetings && meetingType.meetings.length>0">
<li ng-repeat="meeting in meetingType.meetings track by $index">
<a>- {{meeting}}</a>
</li>
</ul>
</li>
</ul>
</td>
</tr>
</table>
javascripts -
'user strict';
angular.module('myApp', [])
.controller('TestCtrl', function($scope) {
$scope.employee = {};
$scope.meetingTypes = {};
$scope.setEmployee = function(employee) {
$scope.employeeId = 1;
//$scope.employee = {};
a($scope.employeeId);
};
var a = function() {
// your service should return this json
$scope.meetingTypes = [{
typeName: 'abc',
meetings: ['meeting1', 'meeting2', 'meeting3']
}, {
typeName: 'def',
meetings: ['meeting4', 'meeting5', 'meeting6']
}, {
typeName: 'ghi',
meetings: ['meeting7', 'meeting8', 'meeting8']
}];
};
});
jsfiddle

AngularJS - Not update table-pagination after http-get success's event

i have a problem. I'm using AngularJs with WebService-Rest, and can't update some table after the call HTTP-GET to WebService. I did tested everything but i can't get it.
Next, i attach the code. Thanks!
HTML:
...
<div class="row" ng-app="SIGA" ng-controller="CreateTable">
<div class="container-fluid">
<table class="table table-striped">
<tbody>
<tr>
<td>Buscar</td>
<td><input type="text" ng-model="search.nombre" /></td>
</tr>
<tr ng-repeat="e in estaciones | filter:paginate| filter:search" ng-class-odd="'odd'">
<td>
<button class="btn">
Detalle
</button>
</td>
<td>{{e.nombre}}</td>
</tr>
</tbody>
</table>
<pagination total-items="totalItems" ng-model="currentPage"
max-size="5" boundary-links="true"
items-per-page="numPerPage" class="pagination-sm">
</pagination>
</div>
</div>
...
JS: ...
app.controller('RestEstacion', function ($rootScope, $http) {
$http.get('http://localhost:8080/sigarest/webresources/entity.estaciones').
success(function(data) {
$rootScope.estaciones = data; UpdateTable($rootScope);
}).
error(function(status) {
alert('error:'+status);
});
});
app.controller('CreateTable', function ($scope,$rootScope) {
$rootScope.predicate = 'nombre';
$rootScope.reverse = true;
$rootScope.currentPage = 1;
$rootScope.order = function (predicate) {
$rootScope.reverse = ($rootScope.predicate === predicate) ? !$rootScope.reverse : false;
$rootScope.predicate = predicate;
};
$rootScope.estaciones = [];
$rootScope.totalItems = $rootScope.estaciones.length;
$rootScope.numPerPage = 5;
$rootScope.paginate = function (value) {
var begin, end, index;
begin = ($rootScope.currentPage - 1) * $rootScope.numPerPage;
end = begin + $rootScope.numPerPage;
index = $rootScope.estaciones.indexOf(value);
return (begin <= index && index < end);
};
});
JS (Update Function):
function UpdateTable($rootScope){
$rootScope.totalItems = $rootScope.estaciones.length;}
** Original Answer (what comments refer to) **
I think you are assigning the get response object rather than the data inside it. Try this:
success(function(response) {
$rootScope.estaciones = response.data;
UpdateTable($rootScope);
}).
** EDIT **
Now that we have established that you are returning data from the API, the real issue appears to be the double controller using $rootScope as a bridge, which can work but is a bit of an anti-pattern in Angular.
The first controller in your app is trying to act like a service, and so really needs to be converted into one. Here is some SAMPLE PSUEDO CODE to give the idea. I do not fully understand your code, like the pagination directive. There should be a click handler in the pagination directive that would call the service method changePagination and pass in the new page number. There should be no need for $rootScope anywhere in this.
JS
app.service('RestEstacionService', function ($http) {
var RestEstacionService = this;
this.apiData = null;
this.tableData = null;
this.currentPage = 1;
this.numPerPage = 5;
this.url = 'http://localhost:8080/sigarest/webresources/entity.estaciones';
this.getData = function (url) {
return $http.get(url).then(function(response) {
RestEstacionService.apiData = response.data;
// do success stuff here
// figure out which page the view should display
// assign a portion of the api data to the tableData variable
})
};
this.changePagination = function (newPage) {
// do your your pagination work here
};
});
app.controller('RestEstacionController', ['$scope', 'RestEstacionService', function ($scope, RestEstacionService) {
$scope.service = RestEstacionService;
RestEstacionService.getData(RestEstacionService.url);
}]);
HTML
<div class="row" ng-app="SIGA" ng-controller="RestEstacionController">
<div class="container-fluid">
<table class="table table-striped">
<tbody>
<tr>
<td>Buscar</td>
<td><input type="text" ng-model="search.nombre" /></td>
</tr>
<tr ng-repeat="row in services.tableData | filter:paginate| filter:search" ng-class-odd="'odd'">
<td>
<button class="btn">
Detalle
</button>
</td>
<td>{{row.nombre}}</td>
</tr>
</tbody>
</table>
<pagination total-items="services.apiData.length" ng-model="services.currentPage"
max-size="5" boundary-links="true"
items-per-page="services.numPerPage" class="pagination-sm">
</pagination>
</div>

How do I tell ui-Bootstrap what content to paginate?

I am using ui-Bootstrap and I am trying to get the pagination working but I seem to be missing something. I have read the documentation and looked at a bunch of plunkers to try and work out how they are specifying which content to paginate but I am having no luck.
Here is what I have done http://plnkr.co/edit/5mfiAcOaGw8z8VinhIQo?p=preview
<section class="main" ng-controller="contentCtrl">
<div ng-repeat="friend in friends">
{{friend.name}}
</div>
<pagination total-items="totalItems" items-per-page="itemsPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
<p>
total Items: {{totalItems}}<br />
Items per page: {{itemsPerPage}}<br />
Current Page: {{currentPage}}
</p>
</section>
Controller:
angular.module('plunker', ['ui.bootstrap'])
.controller('contentCtrl', function ($scope) {
$scope.friends = [
{'name':'Jack'},
{'name':'Tim'},
{'name':'Stuart'},
{'name':'Richard'},
{'name':'Tom'},
{'name':'Frank'},
{'name':'Ted'},
{'name':'Michael'},
{'name':'Albert'},
{'name':'Tobby'},
{'name':'Mick'},
{'name':'Nicholas'},
{'name':'Jesse'},
{'name':'Lex'},
{'name':'Robbie'},
{'name':'Jake'},
{'name':'Levi'},
{'name':'Edward'},
{'name':'Neil'},
{'name':'Hugh'},
{'name':'Hugo'},
{'name':'Yanick'},
{'name':'Matt'},
{'name':'Andrew'},
{'name':'Charles'},
{'name':'Oliver'},
{'name':'Robin'},
{'name':'Harry'},
{'name':'James'},
{'name':'Kelvin'},
{'name':'David'},
{'name':'Paul'}
];
$scope.totalItems = 64;
$scope.itemsPerPage = 10
$scope.currentPage = 1;
$scope.setPage = function (pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
console.log('Page changed to: ' + $scope.currentPage);
};
$scope.maxSize = 5;
$scope.bigTotalItems = 175;
$scope.bigCurrentPage = 1;
});
I could simply add the following references:
bootstrap-css
angular.js
angular-ui-bootstrap
Your body could look like this:
<html ng-app="friends">
<head>
...
</head>
<body>
<h4>Paginated Friends</h4>
<section class="main" ng-controller="contentCtrl">
<div ng-repeat="friend in filteredFriends">
{{friend.name}}
</div>
<pagination total-items="totalItems" items-per-page="itemsPerPage"
ng-model="currentPage" ng-change="pageChanged()"></pagination>
<p>
Total items: {{totalItems}}<br />
Items per page: {{itemsPerPage}}<br />
Current Page: {{currentPage}}
</p>
</section>
</body>
</html>
Then define the following controller:
var app = angular.module('plunker', ['ngResource', 'ui.bootstrap']);
app.factory('friendsFactory', function($resource) {
return $resource('friends.json');
});
app.controller('contentCtrl', function ($scope, friendsFactory) {
$scope.friends = friendsFactory.query();
$scope.itemsPerPage = 10
$scope.currentPage = 1;
// $scope.maxSize = 5;
// $scope.bigTotalItems = 175;
// $scope.bigCurrentPage = 1;
$scope.pageCount = function () {
return Math.ceil($scope.friends.length / $scope.itemsPerPage);
};
$scope.friends.$promise.then(function () {
$scope.totalItems = $scope.friends.length;
$scope.$watch('currentPage + itemsPerPage', function() {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
end = begin + $scope.itemsPerPage;
$scope.filteredFriends = $scope.friends.slice(begin, end);
});
});
});
ui-bootstrap 0.10 doesn't use ng-model to update current page.
use page="currentPage" to show current page.
use on-select-page="setPage(page)" to change current page.
Example's here:
http://plnkr.co/edit/UIWIeDSKIK4bG96eoJmt?p=preview
if you want to use ng-model. update your ui-bootstrap version to 0.11
You can use the variables that are created in your ng-repeat . This works. I use it until I have to change it.
ng-repeat="friend in friends.slice(((currentPage-1)*itemsPerPage), ((currentPage)*itemsPerPage)) track by $index"
However I have found that the best solution to this problem is to create a filter and chain it. Put it last in the chain since you would probably want to use other filters before it. Here is an example using an orderby filter. The difference is that you can then order your whole array and then paginate and show just the part that you would like to show.
function paginateFilter() {
return function (friends, currentPage, itemsPerPage) {
var filteredFlowers = flowers.slice(((currentPage-1)*itemsPerPage), ((currentPage)*itemsPerPage))
return filteredFriends;
};
}
And here is the html. You will have to use a filter with multiple variables.
ng-repeat="friend in main.friends |orderBy: 'name' | paginate: main.currentPage: main.itemsPerPage">
Where main is the controllerAs name.
implementation using angularjs 1.5 components and Typescript
searchresults.controller.ts
import {Group as Groups, GroupSearchCriteria as GroupsSearchCriteria, GroupSearchResults as GroupsSearchResults } from "../../models/Groups";
import GroupsService from "groups/groups.service";
interface ISearchResultsController {
groups: Groups[];
groupsSearchCriteria: GroupsSearchCriteria;
pageChanged(): void;
splitGroupsPagination(): void;
}
class SearchResultsController implements ISearchResultsController {
groups: Groups[];
groupsSearchCriteria: GroupsSearchCriteria;
groupresSearchCriteria: any;
TotalResults: any;
CurrentPage: any;
ResultsPerPage: any;
pageCount: number;
begin: number;
end: number;
sortedResults: Groups[];
constructor(private groupsService: GroupsService, private groupSearchResults: GroupsSearchResults) {
var isolatedScopeSearchResults = this;
this.groups = isolatedScopeSearchResults.groupsService.searchCallback.SearchResults;
this.groupresSearchCriteria = isolatedScopeSearchResults.groupsService.searchCallback.Criteria;
this.TotalResults = 7;
this.CurrentPage = 1;
this.ResultsPerPage = 5;
}
$onInit() {
this.splitGroupsPagination();
}
splitGroupsPagination() {
this.pageCount = Math.ceil(this.TotalResults / this.ResultsPerPage);
this.begin = ((this.CurrentPage - 1) * this.ResultsPerPage);
this.end = this.begin + this.ResultsPerPage;
this.sortedResults = this.groups.slice(this.begin, this.end);
}
pageChanged() {
this.splitGroupsPagination();
}
}
export default SearchResultsController;
searchresults.component.ts
import SearchResultsController from "./searchresults.controller";
class SearchResultsComponent implements ng.IComponentOptions {
template = `
<div id="groupSearchResults" class="box-response">
<!-- start: results header with btn add-->
<div class="box-header">
<h2><span>Search Results: </span><span>{{$ctrl.groups.length}}</span> <span>Term: {{$ctrl.groupresSearchCriteria.SearchDescription}}</span></h2>
</div>
<div class="box-content">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<td>Name</td>
<td>Id</td>
<td>Consent Group</td>
<td>Permitted Uris</td>
<td>Actions</td>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="group in $ctrl.sortedResults">
<td>{{group.Name}}</td>
<td>{{group.Id}}</td>
<td>{{group.IncludeInConsentGroups}}</td>
<td>{{group.PermittedUris}}</td>
<td>
<a class="btn btn-success" href="" ui-sref="edit({editgroupId:group.Id})"><i class="fa fa-edit"></i></a>
</td>
</tr>
</tbody>
</table>
</div>
<uib-pagination total-items="$ctrl.TotalResults" ng-model="$ctrl.CurrentPage" items-per-page="$ctrl.ResultsPerPage" ng-change="$ctrl.pageChanged()"></uib-pagination>
</div>
`;
controller = ['GroupsService',SearchResultsController];
}
export default SearchResultsComponent;

Resources