show 2 array through ng-repeat error - arrays

i am trying to make a table from 2 arrays in AngularJS one array contains Employees name and other array contain Services Name and rest of the cells contain check boxes but when i do i got error Error: [ngRepeat:dupes]
here is my AngularJS code
var model = angular.module('wizard', ['ngRoute'])
.config(["$routeProvider", function ($routeProvider) {
$routeProvider.when("/m5", {
controller: "model5Controller",
templateUrl: "/templates/m5.html"
});
$routeProvider.otherwise({ redirectTo: '/' });
}]);
var model5Controller = ["$scope", "$http", "$window", function ($scope,
$http, $window) {
$scope.PBA = [];
$scope.SOB = [];
$http.get('/Test/GetPBA').
then(
function (result) {
//success
$scope.PBA = result.data;
},
function () {
//error
});
$http.get('/Test/GetSOB').
then(
function (result) {
//success
$scope.SOB = result.data;
},
function () {
//error
});
$scope.save = function () {
//to be written
};
}];
GetPBA/GetSOB returns JSON type Array of List
both contain properties like Id, Name
here is my html
<div>
<form ng-submit="save()">
<table border="1">
<tr>
<td><strong>Services</strong></td>
<td ng-repeat="e in PBA">{{e.Name}}</td>
</td>
<tr ng-repeat="i in SOB">
<td>{{i.Name}}</td>
<td ng-repeat="e in PBA">
<input type="checkbox" name="{{e.Id}}" />
</td>
</tr>
</table>
</form>

Try this
<tr ng-repeat="i in SOB track by $index">
<td>{{i.Name}}</td>
<td ng-repeat="e in PBA track by $index">
<input type="checkbox" name="{{e.Id}}" />
</td>
</tr>

Related

AngularJS - DOM not updated in Chrome and Mozilla

I'm using angularjs and angular-ui-bootstrap to make a table and page some data, which I get from an API.
I've made sure my service receives the correct data and that the requests are built properly. My pageChange function is properly triggered and my first page gets loaded successfully.
So I have the following controller setup:
(function () {
'use strict';
initContacts.$inject = ['$scope', '$http'];
angular.module('app')
.config(function ($locationProvider) {
$locationProvider.html5Mode(true);
});
angular.module('app', ['ui.bootstrap']).controller('contactSearchController', initContacts);
function initContacts($scope, $http) {
$scope.contacts = [];
$scope.totalItems = 0;
$scope.pages = 0;
$scope.currentPage = 0;
$scope.maxPageLinksShown = 5;
if (window.location.hash !== '') {
$scope.currentPage = window.location.hash.replace('#', '');
}
$http.get("/api/ContactApi/GetPage?pageIndex=" + ($scope.currentPage - 1)).success(function (data) {
$scope.contacts = data.Contacts;
$scope.totalItems = data.Count;
$scope.PageSize = data.Contacts.length;
$scope.pages = Math.ceil((data.Count / $scope.PageSize));
});
$scope.pageChanged = function () {
$http.get("/api/ContactApi/GetPage?pageIndex=" + ($scope.currentPage - 1))
.success(function (data) {
$scope.contacts = data.Contacts;
});
};
}
}
})();
And in my view I have:
<div ng-app="app" ng-controller="contactSearchController">
<table class="table table-striped table-hover contact-search-table">
<thead>
<tr>
<td class="contact-title">
Titel
</td>
<td class="department">
Afdeling
</td>
<td class="name">
Navn
</td>
<td class="work-phone">
Telefon
</td>
<td class="mobile">
Mobile
</td>
<td class="email">
Email
</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in contacts">
<td class="contact-title">{{value.Title}}</td>
<td class="department">{{value.Department}}</td>
<td class="name">{{value.FullName}}</td>
<td class="work-phone">{{value.WorkPhone}}</td>
<td class="mobile">{{value.WorkMobile}}</td>
<td class="email">{{value.Email}}</td>
</tr>
</tbody>
</table>
<div class="col-xs-12 pager-container">
<ul uib-pagination total-items="totalItems" ng-model="currentPage" ng-change="pageChanged()" max-size="maxPageLinksShown" class="pagination-sm" boundary-links="true" num-pages="pages"></ul>
</div>
Now this works to some extent.
My problem
When I click the page links, the pageChanged() function is called, I get the data from my api and it's all correct, the list in the scope appears to be updated fine, but the table in my view doesn't change.
This solution works fine ONLY in IE ! (who would have thought huh...)
No exceptions get thrown.
I swear this was working yesterday.
Any help is much appreciated!
EDIT
What I've tried:
-Putting the assignment of the contacts in an $apply like so:
$scope.pageChanged = function () {
$http.get("/api/ContactApi/GetPage?pageIndex=" + ($scope.currentPage - 1))
.success(function (data) {
$scope.$apply(function () { // apply
$scope.contacts = data.Contacts;
});
});
};
I got a "$digest already in progress" error from this.
tried to wrap the apply in a timeout like so:
$timeout(function(){ //any code in here will automatically have an apply run afterwards });
Got rid of the error but the DOM still won't update.
I had such a problem and I solved it using $scope.$apply:
$scope.pageChanged = function () {
$http.get("/api/ContactApi/GetPage?pageIndex=" + ($scope.currentPage - 1))
.success(function (data) {
$scope.$apply(function () { // apply
$scope.contacts = data.Contacts;
});
});
};
You should use $scope.$applyAsync instead. It will be applied to the next digest cycle.
If you need to target all the $scopes of your AngularJS application, use $rootScope.$applyAsync instead.
Official doc
Okay so what worked in this situation was changing the way I'm visualizing the ng-repeat like so:
<tr ng-repeat="contact in getContacts()">
<td class="contact-title">{{contact.Title}}</td>
<td class="department">{{contact.Department}}</td>
<td class="name">{{contact.FullName}}</td>
<td class="work-phone">{{contact.WorkPhone}}</td>
<td class="mobile">{{contact.WorkMobile}}</td>
<td class="email">{{contact.Email}}</td>
</tr>
And heres the getContacts() function:
$scope.getContacts = function () {
var data = $scope.contacts;
if (data instanceof Array) {
return data;
} else {
return [data];
}
}
I don't really know why that works, but it does.

Why is my ng-repeat not showing pulled data?

I am following an Angular tutorial where I am trying to format my code in John Papa's style guide for Angular 1.
I am currently trying to display a table of github repos from any username that is inputted into the search form. Everything else displays except for the repos.
Please find a link to the code on plunker.co -> here.
This is the html template code below:
<div ng-controller="UserController as github">
<h4>{{ github.user.name }}</h4>
{{ github.error }}
<img ng-src="{{ github.user.avatar_url }}" title="{{ github.user.name }}" />
</div>
<div class="input-field col s12">
<select ng-model="github.repoSortOrder">
<option value="+name">Name</option>
<option value="-stargazers_count">Stars</option>
<option value="+language">Language</option>
</select>
<label>Order By:</label>
</div>
<table class="col">
<thead>
<tr>
<th>Name</th>
<th>Stars</th>
<th>Language</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="'repo in github.repos | orderBy: github.repoSortOrder'">
<td>{{ repo.name }}</td>
<td>{{ repo.stargazers_count | number }}</td>
<td>{{ repo.language }}</td>
</tr>
</tbody>
</table>
<br>
Back to search
<script type="text/javascript">
$(document).ready(function() {
$('select').material_select();
});
</script>
And this is the UserController js code:
// Code goes here
(function() {
angular
.module('app.github')
.controller('UserController', ['github', '$routeParams', '$log', function UserController(github, $routeParams, $log) {
var vm = this;
var onUserComplete = function(data) {
vm.user = data;
github.getRepos(vm.user)
.then(onRepos, onError);
};
var onRepos = function(data) {
$log.info('getting data');
vm.repos = data;
$log.info('finished getting data');
};
var onError = function(reason) {
vm.error = "Boo! Could not fetch the user data!";
};
vm.username = $routeParams.username;
vm.repoSortOrder = "-stargazers_count";
github.getUser(vm.username).then(onUserComplete, onError);
}]);
}());
Lastly, this is the 'github' service as a dependancy to the controller:
(function() {
angular
.module('app.github')
.factory('github', ['$http', '$log', function github($http, $log) {
var getUser = function(username) {
return $http.get("https://api.github.com/users/" + username)
.then(function(response) {
return response.data;
});
};
var getRepos = function(user) {
$log.info('starting getRepos()');
return $http.get(user.repos_url)
.then(function(response) {
$log.info('ending getRepos()');
return response.data;
});
};
return {
getUser: getUser,
getRepos: getRepos
};
}]);
})();
May I have someones input in this please?
Thanks
AlvSovereign
This is wrapped in single quotes which angular will evaluate as a string:
<tr ng-repeat="'repo in github.repos | orderBy: github.repoSortOrder'">
It needs to be:
<tr ng-repeat="repo in github.repos | orderBy: github.repoSortOrder">
The error is on the first line. You bound the controller to only that div.
<div ng-controller="UserController as github">//here
<h4>{{ github.user.name }}</h4>
{{ github.error }}
<img ng-src="{{ github.user.avatar_url }}" title="{{ github.user.name }}" />
</div>
Putting a div around the whole thing should fix this. Along with the ng-repeat mistake mentioned below by #robj.

Bind data to table using ng-repeat on ng-change of dropdownlist

I want data to appear in table according to selected value. I want to bind data to table after data is fetched when ng-change of dropdownlist is triggered
<div ng-app="myapp" ng-controller="prodctrl" >
<select id="BrandDropdown" class="InstanceList" ng-change="GetBrandProd()" ng-model="Products">
<option>Select Brand</option>
#if (ViewBag.dataset != null)
{
foreach (string str in (string[])ViewBag.dataset)
{
<option value='#str.Split('/')[0]'>#str.Split('/')[1]</option>
}
}
</select>
<table ng-model="Products">
<tr ng-repeat="P in Products track by $index">
<td >{{x.Id}}</td>
<td >{{X.Rank}}</td>
<td >{{x.Name}}</td>
</tr>
</table>
</div>
this the code
var app = angular.module('myapp', []);
app.controller('prodctrl', function ($scope, $http) {
$scope.GetBrandProd = function () {
var Id = $('#BrandDropdown').val();
$http({
method: "GET",
url: "/Home/GetProdBrand",
params: {
id:Id
}
})
.success(function (response) {
$scope.Products = response.records;
});
}
})
I am able to get the data successfully in response.records. but after i get data nothing happens

Breaking the ice on angular

I have a view:
<div id="productList" ng-controller="ProductController">
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th width="100%">Item ID</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in productItems">
<td><input type="checkbox" /></td>
<td><% item.ID %></td>
</tr>
</tbody>
</table>
</div>
I have a controller:
var TestApp = angular.module('TestApp', [], function( $interpolateProvider ) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
});
TestApp.controller('ProductController', function ( $scope ) {
ProductRepository.GetPaginatedProducts();
$scope.productItems = ProductRepository.Model;
});
I have a model:
var ProductRepository = function ()
{
return {
Model: null,
GetPaginatedProducts: function()
{
$.ajax( {
"url": Test.URL + "/json/products/paginated",
"dataType": "json",
"method": "post",
"success": function( data )
{
ProductRepository.Model = data;
}
} );
},
}
}
When the ajax finished, it updates the ProductRepository.Model data variable which I want the angular controller scope.productItems to work off of.
This is my first time using angular and i think I've missed the point,
Why is the table not updating with the information?
Please see here for sample ajax call http://plnkr.co/edit/5CiC8MWiwo010nwu32he?p=preview
var TestApp = angular.module('plunker', []);
TestApp.factory('ProductRepository', function($http, $q) {
var Model = [];
return {
Model: Model,
GetPaginatedProducts: function() {
var deferred = $q.defer();
$http.get('paginated.json').then(
//sucess
function(result) {
deferred.resolve(result.data)
}
//error
, function() {});
return deferred.promise;
}
};
})
TestApp.controller('ProductController', function($scope, ProductRepository) {
$scope.productItems = [];
ProductRepository.GetPaginatedProducts().then(function(data) {
//success
$scope.productItems = data;
},
//error
function() {
alert("can't get data");
})
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="plunker">
<div id="productList" ng-controller="ProductController">
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th width="100%">Item ID</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in productItems">
<td>
<input type="checkbox" />
</td>
<td>{{item.ID}}</td>
</tr>
</tbody>
</table>
</div>
</div>
As #tymeJV stated in the comment, you should use $http or $resource (or restangular) to perform the data access. If you are updating values outside of Angular's framework, it has no way of knowing that data has changed. By using something like $http or $resource, Angular is aware when an event has occurred that can change values and automatically checks for updates.
Alternately, you could manually issues an $apply() to essentially handle the digest update manually (ensuring Angular goes through a digest cycle when you've changed values outside of Angular). Take a look at the documentation on $apply() at https://docs.angularjs.org/api/ng/type/$rootScope.Scope .
However, your best bet is to use the Angular approach in the first place and avoid using jQuery for this.

Angularjs ng-select selected value not set

I am trying to populate a form to edit a user list.
index.html:
<h1>Users</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="u in users" data-ng-click="select(u)">
<td>{{u.id}}</td>
<td>{{u.username}}</td>
<td>{{u.role.title}}</td>
</tr>
</tbody>
</table>
<form>
<label for="inputUsername">Username</label>
<input data-ng-model="selectedUser.username" id="inputUsername" type="text">
<select data-ng-model="selectedUser.role"
data-ng-options="r as r.title for r in roles"
data-ng-change="">
</select>
</form>
<pre>{{selectedUser |json}}</pre>
controllers.js:
angular.module('test-select')
.controller('IndexCtrl',
['$scope', 'Restangular', function($scope, Restangular) {
$scope.selectedUser = null;
Restangular.all("roles").getList().then(function(roles) {
$scope.roles = roles;
});
Restangular.all("users").getList().then(function(users) {
$scope.users = users;
});
$scope.select = function(user) {
$scope.selectedUser = user;
};
}]);
What I want to achieve is, when I click on a row on the table I can edit the selected user in the form (to save the new values) Everything works fine, except for the users role. If I click on a row, the selected user role is not updated.
I think that has to do with the fact thaT the role list via Restangular call. Has anyone an Idea how I can solve this problem elegantly?
PS: I am using angular 1.2-rc2.
BR, Rene
The following solution works but I think it is not very elegant:
index.html:
<h1>Users</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="u in users" data-ng-click="select(u)">
<td>{{u.id}}</td>
<td>{{u.username}}</td>
<td>{{u.role.title}}</td>
</tr>
</tbody>
</table>
<form>
<label for="inputUsername">Username</label>
<input data-ng-model="selectedUser.username" id="inputUsername" type="text">
<select data-ng-model="selectedUser.role.id"
data-ng-options="r.id as r.title for r in roles"
data-ng-change="update()">
</select>
</form>
controller.js:
'use strict';
/* Controllers */
angular.module('test-select')
.controller('IndexCtrl',
['$scope', 'Restangular', '$resource', function($scope, Restangular, $resource) {
$scope.selectedUser = null;
Restangular.all("roles").getList().then(function(roles) {
$scope.roles = roles;
});
Restangular.all("users").getList().then(function(users) {
$scope.users = users;
});
$scope.select = function(user) {
$scope.selectedUser = user;
};
$scope.update = function() {
var role = _.find($scope.roles, function(role){
return role.id === $scope.selectedUser.role.id;
});
$scope.selectedUser.role.title = role.title;
$scope.selectedUser.role.bitMask = role.bitMask;
}
}]);

Resources