AngularJS - HTML not updating on variable change - angularjs

I am trying to learn AngularJS and i am making a test app.
I have a table that gets populated with data returned from a WebService (list of publishers) via $http.get().
When the user clicks a row (publisher) i want to fill a second table with the list of employees of the selected publisher. By using the F12 tools (Network+Console) i see that the data is returned but the second table is not filled/updated.
html
<!DOCTYPE html>
<html ng-app="myApp">
<head lang="en">
<meta charset="UTF-8">
<link rel="stylesheet" href="css/style.css" type="text/css" />
<script src=""></script>
<script src="js/angular.js"></script>
<script src="js/scripts.js"></script>
<script src="js/app.js"></script>
<title>My SPA</title>
</head>
<body>
<header>
<h1 id="page-title">Header</h1>
<nav>
<ul>
<li>Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
</ul>
</nav>
</header>
<div ng-controller='PublishersController' class="table-wrapper">
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in publishers[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='pub in publishers' ng-click='getPublishersEmployees(pub.pub_id)'>
<td ng-repeat='(key,val) in pub'>{{val}}</td>
</tr>
</tbody>
</table>
</div>
<div ng-controller='PublishersController' class="table-wrapper">
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in employees[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='employee in employees'>
<td ng-repeat='(key,val) in employee'>{{val}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
JS
var urlBase = "http://localhost:2041";
var app = angular.module('myApp', []);
app.factory('myFactory', ['$http', function ($http) {
var webAPI = '/api/query';
var webService = urlBase + webAPI;
var myFactory = {};
myFactory.getCategories = function () {
return $http.get(webService + '/getCategories');
};
myFactory.getCategorySalesByMonth = function (id) {
return $http.get(webService + '/getCategorySalesByMonth/' + id);
};
myFactory.getPublishers = function () {
return $http.get(webService + '/getPublishers');
};
myFactory.getPublishersEmployees = function (id) {
return $http.get(webService + '/getPublishersEmployees/' + id);
};
return myFactory;
}]);
app.controller('PublishersController', ['$scope', 'myFactory',
function ($scope, myFactory) {
$scope.status;
$scope.publishers;
$scope.employees;
getPublishers();
function getPublishers() {
myFactory.getPublishers()
.success(function (publishers) {
$scope.publishers = publishers;
})
.error(function (error) {
$scope.status = 'Unable to load publishers data: ' + error.message;
});
}
$scope.getPublishersEmployees = function (id) {
myFactory.getPublishersEmployees(id)
.success(function (employees) {
$scope.employees = employees;
console.log($scope.employees);
})
.error(function (error) {
$scope.status = 'Error retrieving employees! ' + error.message;
});
};
}]);
What am i doing wrong?

The problem is you use separate controllers for PublishersController and EmployeesController. Angular will create separate scopes for your controllers. Therefore, when you assign $scope.employees = employees in your PublishersController, it does not reflect on the scope created by EmployeesController
Try:
<div ng-controller='PublishersController' class="table-wrapper">
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in publishers[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='pub in publishers' ng-click='getPublishersEmployees(pub.pub_id)'>
<td ng-repeat='(key,val) in pub'>{{val}}</td>
</tr>
</tbody>
</table>
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in employees[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='employee in employees'>
<td ng-repeat='(key,val) in employee'>{{val}}</td>
</tr>
</tbody>
</table>
</div>
That solution above is just to point out your problem. I don't know your application design, you may not follow this solution but restructure your code to best fit your application design (like storing the employees in a shared service,...).
Here I propose another solution but I'm not sure if it fits with your application. You just use your original HTML code with PublishersController and EmployeesController. In your PublishersController, your could broadcast an event from rootScope:
.success(function (employees) {
$rootScope.$broadcast("employeeLoaded",employees);
})
Don't forget to inject $rootScope to your PublishersController:
app.controller('PublishersController', ['$scope', 'myFactory','$rootScope',
function ($scope, myFactory,$rootScope)
In your EmployeesController, you could subscribe to this event:
$scope.$on("employeeLoaded",function (event,employees){
$scope.employees = employees;
});
For more information about event in angular, check out Working with $scope.$emit and $scope.$on

Related

AngularJS - Multiple Modules/Controllers on different pages - only selecting first controller for both pages

I am extremely new to AngularJS and JavaScript in general so any help would be appreciated!
I have two data sources Users and Pets - both are Array objects and I want them to display in a table on different pages of my site. I have an app.module.js which calls the module petsapp or usersapp Currently the controller only being called is the petspp.
I have tried to use $scope but I don't really know what I'm doing!
I currently have set up an app.module.js, which looks like this (but possibly wrong:
(function(){
'use strict';
angular.module('petsapp',[]);
angular.module('usersapp',[]);
})();
another file called **Pets.controller.js:**
(function () {
'use strict';
angular
.module('petsapp')
.controller('PetsController', function ($scope) {
})
PetsController.$inject = ['$http'];
function PetsController($http) {
var vm = this;
vm.pets = [];
vm.getAll = getAll();
vm.deletePet = deletePet();
init();
function init(){
getAll();
}
and a users.controller.js which looks like this:
(function () {
'use strict';
angular
.module('usersapp')
.controller('UsersController', UsersController)
UsersController.$inject = ['$http'];
function UsersController($http) {
var vm = this;
vm.users = [];
vm.getAll = getAll()
vm.delete = deleteUser()
init();
function init(){
getAll();
}
my pets html (working) is:
<!DOCTYPE html>
<script type="text/javascript"src="/static/angular.min.js" th:src="#{/angular.min.js}"></script>
<script type="text/javascript"src="/static/app/app.module.js" th:src="#{/app/app.module.js}"></script>
<script type="text/javascript"src="/static/app/pets.controller.js" th:src="#{/app/pets.controller.js}"></script></head>
<header th:insert="fragments.html :: nav"></header>
<body ng-app="petsapp" ng-controller="PetsController as vm">
<!-- Page content goes here -->
<div>
<div class="row">
<div class="col-lg-offset-2 col-lg-8">
<!-- Display animals in a table -->
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Gender</th>
<th>Breed</th>
<th>Age</th>
<th>OK with Children?</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="pet in vm.pets">
<td>{{pet.id}}</td>
<td>{{pet.animalName}}</td>
<td>{{pet.animal}}</td>
<td>{{pet.gender}}</td>
<td>{{pet.breed}}</td>
<td>{{pet.age}}</td>
<td>{{pet.compWithChildren}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>.
my users html (not working as it is only pulling the pets.controllers.js) is:
<head th:insert="fragments.html :: headerfiles">
<script type="text/javascript"src="/static/angular.min.js" th:src="#{/angular.min.js}"></script>
<script type="text/javascript"src="/static/app/app.module.js" th:src="#{/app/app.module.js}"></script>
<script type="text/javascript"src="/static/app/users.controller.js" th:src="#{/app/users.controller.js}"></script>
</head>
<header th:insert="fragments.html :: nav"></header>
<body ng-app="usersapp" ng-controller="UsersController as vm">
<!-- Page content goes here -->
<div>
<div class="row">
<div class="col-lg-offset-2 col-lg-8">
<!-- Display animals in a table -->
<table class="table">
<thead>
<tr>
<th>User Name</th>
<th>Roles</th>
<th>Email</th>
<th>Contact Number</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="userdetail in vm.users">
<td>{{userdetail.username}}</td>
<td>{{userdetail.roles}}</td>
<td>{{userdetail.email}}</td>
<td>{{userdetail.contactNo}}</td>
<td>
<!--Only Admin can delete rows --->
<button class="btn btn-danger" ng-click="vm.deleteUser(userdetail.id)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html
I think the problem is in the app.module.js file where I've defined two modules?
do I need to combine both controllers into one file? if so how do I implement that?

angularjs with jquery datatable search button does not work

When i try to use jquery datatable with angularjs, search button doesn't work. but if i bind the data using pure asp.net mvc by actionresult method, it works correctly.
I bind the data from user-role.js and i'm using ng-repeat to bind them.
my angularjs version is 1.7.2
jquery.datatble version is 1.10.16
cshtml codes below.
<script type="text/javascript" src="~/Scripts/app/user-role.js"></script>
<div ng-app="userRoleGridApp" ng-controller="userRoleGridCtrl">
<div class="container">
<div class="row">
<div class="col-md-9">
<div class="table-responsive">
<table class="table" id="user-table">
<thead>
<tr>
<th>UserId</th>
<th>User Name</th>
<th>Name Surname</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in Users track by $index">
<th>{{x.UserId}}</th>
<th>{{x.UserName}}</th>
<th>{{x.NameSurname}}</th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#user-table').DataTable({
dom: 'Bfrtip',
buttons: [
'copyHtml5',
'excelHtml5',
//'csvHtml5',
'pdfHtml5'
]
});
});
</script>
Js side
var app = angular.module("userRoleGridApp",
['ngAnimate',
'ngRoute']);
var baseUrl = location.origin;
app.controller("userRoleGridCtrl", function ($scope, $http) {
$scope.Users = {};
initUser();
function initUser() {
$http({
method: "get",
url: baseUrl + "/UserRole/GetUsers"
}).then(function (response) {
$scope.Users = response.data;
}, function () {
alert("Error Occur");
});
}
});

Angular Js swap columns in table

I would like to swap 2 columns in a table. Finally, I succeeded the change, but only the data. The attributes of the cell (style, id, class) didn't move. I tried to move attributes with jquery (i know, not an elegant method), but it was only symptomatic treatment. After clicking the data reload button, the attributes restored.
How can I change the columns order with all attributes?
my code: https://codepen.io/qwertz_/pen/YxWMBO
<!DOCTYPE html>
<html>
<head>
<title>angT</title>
<script type="text/javascript" src="http://code.angularjs.org/angular-1.0.0rc10.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<style>
th, td{padding: 3px 20px;border: 1px solid red;}
</style>
</head>
<body>
<div ng-controller="MyCtrl" ng-app="myApp">
<button ng-click="swap(0)">first2second</button>
<button ng-click="reload()">reload</button>
<table id="myTable" >
<tr ng-repeat="row in ths">
<th class="oo1">{{col(row, 0)}}</th>
<th class="oo2">{{col(row, 1)}}</th>
<th class="oo3">{{col(row, 2)}}</th>
<th class="oo4">{{col(row, 3)}}</th>
</tr>
<tr ng-repeat="row in rows">
<td class="o1" style="background-color:yellow;">{{col(row, 0)}}</td>
<td class="o2" style="background-color:pink;">{{col(row, 1)}}</td>
<td class="o3" style="background-color:green;">{{col(row, 2)}}</td>
<td class="o4" style="background-color:blue;">{{col(row, 3)}}</td>
</tr>
</table>
</div>
<script type='text/javascript'>
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.mycol = new Array();
$scope.mycol[0] = 'id';
$scope.mycol[1] = 'name';
$scope.mycol[2] = 'db';
$scope.mycol[3] = 'let';
$scope.reload = function()
{
$scope.rows=[{id:parseInt(Math.random()*10000),name:"Liv","db":21,let:"r"},{id:parseInt(Math.random()*10000),name:"Mike",db:30,let:"u"}];
};
$scope.swap = function(i) {
var temp = $scope.mycol[i];
$scope.mycol[i] = $scope.mycol[(i+1)];
$scope.mycol[(i+1)] = temp;
};
$scope.col = function(row, mycol) {
return row[$scope.mycol[mycol]];
};
$scope.reload();
$scope.ths=[{id:"id",name:"name","db":"db",let:"letter"}];
}
</script>
</body>
Thx a lot
Simple way
You can bind colors to header name as:
$scope.styles = {
id: "yellow",
name: "pink"
};
and table will look like:
<tr ng-repeat="row in rows">
<td class="o1" ng-style="{'background-color':styles[mycol[0]]}">{{col(row, 0)}}</td>
<td class="o2" ng-style="{'background-color':styles[mycol[1]]}">{{col(row, 1)}}</td>
<td class="o3" style="background-color:green;">{{col(row, 2)}}</td>
<td class="o4" style="background-color:blue;">{{col(row, 3)}}</td>
</tr>
Once header value changes, colors will change too
Codepen DEMO
More complicated but generic
You can achieve it by replacing all table with directive (headers + data) and by using $compile rebuild all HTML table.

Angular JS - dynamically add custom href link to value in table using ng-repeat based on a different value.

I am creating a table using ng-repeat that display some tickets info. Currently in the column "Ticket No" I am adding href link (when user click on the "Ticket No" it will open new tab and the URL will take the ticket no as parameter.
This a plunker I've created so it can show functionality as described above http://plnkr.co/edit/GB8WWz?p=preview
The problem I have now is that the href link might vary and it depends on the account column value. So if my "account = foo" set the href link of the Ticket No to "http://myfoopage.foo/ticketid...etc". If my "account = boo" set the href link for the Ticket No to "http://myboopage.boo/ticketid...etc".
Any idea on how to approach that ?
scriptang.js
angular.module('plunker', ['ui.bootstrap']);
function ListCtrl($scope, $dialog) {
$scope.items = [
{ticket: '123', description: 'foo desc',account:'foo'},
{ticket: '111', description: 'boo desc',account:'boo'},
{ticket: '222', description: 'eco desc',account:'eco'}
];
}
// the dialog is injected in the specified controller
function EditCtrl($scope, item, dialog){
$scope.item = item;
$scope.save = function() {
dialog.close($scope.item);
};
$scope.close = function(){
dialog.close(undefined);
};
}
index.html
<!doctype html>
<html ng-app="plunker">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script src="http://angular-ui.github.com/bootstrap/ui-bootstrap-tpls-0.1.0.js"></script>
<script src="scriptang.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="ListCtrl">
<table class="table table-bordered">
<thead>
<tr>
<th>Ticket No</th>
<th>Description</th>
<th>Account</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>{{item.ticket}}</td>
<td>{{item.description}}</td>
<td>{{item.account}}</td>
<td><button class="btn btn-primary" ng-click="edit(item)">Edit</button></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Updated plnkr here, I've made use of the ng-attr directive in combination with a function that creates an url.
$scope.getUrl = function (item) {
var url = '';
if(item.account === 'foo')
url = 'http://mywebpage.foo';
else
url = 'http://mwebpage.boo';
url += '/ticketid='+item.ticket
return url;
}

bootstrap-table not rendering upon updating model in Angular

Hi I am not able to render table using bootstrap-table and angular. here is my code, I think I need to call bootstrap-table init method in angular ajax call. Can some one guide me on how to do this..?
angular
.module('reports')
.controller(
'ReportCtrl',
[
'$scope',
'$http',
'ngProgress',
function($scope, $http, ngProgress) {
var vm = this;
vm.mdp = {};
vm.mdp.data = [];
vm.mdp.columns = [];
$scope.submit = function() {
var report = $scope.tab;
$http.post('/reports/cmd/getData', {
report : report,
date : createdAfter
}).success(function(data) {
vm.mdp.data = data;
$.each(data[0], function(key, value){
vm.mdp.columns.push(key);
});
}).error(function(error) {
alert(error);
});
};
} ]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="mdp" class="panel" ng-controller="ReportCtrl as report" ng-show="panel.isSelected('mdp')">
<table data-toggle="table" data-show-columns="true" data-search="true" data-show-export="true" data-pagination="true" data-height="299">
<thead>
<tr>
<th ng-repeat="c in report.mdp.columns" data-field= {{c}} >{{ c }}</th>
</tr>
</thead>
<tr ng-repeat="r in report.mdp.data">
<td ng-repeat="c in report.mdp.columns">{{ r[c] }}</td>
</tr>
</table>
</div>
Integrating Bootstrap Table with Angular is solved here:
https://github.com/wenzhixin/bootstrap-table/issues/165
https://github.com/AkramKamal/bootstrap-table-examples/tree/master/integrate
I have some minor changes in my implementation of this solution which I will upload to Github / JSFiddle shortly. But the links above will allow you to get going.

Resources