AngularJS Best Practices for modifying view - angularjs

I currently have an Angular application with one module. This module defines a controller and a service. I'm currently using the service to update my view. Should services update view logic? Or should this be done in a separate Angular component?
index.html
<div ng-controller="AppController as AppCtrl">
<div id="grid1" ui-grid="{ data: myData }" class="grid"></div>
<button ng-click="AppCtrl.getPeople()" ng-model="AppCtrl.getPeopleButtonText" ng-bind="AppCtrl.getPeopleButtonText"></button>
<button ng-click="AppCtrl.clearPeople()">Clear</button>
{{AppCtrl.errorMessage}}
</div>
app.js
angular.module('app', ['ui.grid'])
.controller('AppController', ['$scope', "PersonService", function ($scope, PersonService) {
var controllerScope = this;
controllerScope.getPeopleButtonText = "Get People";
this.getPeople = function(){
PersonService.getPeople($scope, controllerScope);
};
this.clearPeople = function(){
PersonService.clearPeople($scope, controllerScope);
};
}])
.service("PersonService", ["$http", function($http) {
var refreshCount = 0;
this.getPeople = function(rootScope, controllerScope){
var sampleData = [
{
"firstName": "Cox",
"lastName": "Carney",
"company": "Enormo",
"employed": refreshCount%2 == 1
},
{
"firstName": "Lorraine",
"lastName": "Wise",
"company": "Comveyer",
"employed": refreshCount%2 == 0
},
{
"firstName": "Nancy",
"lastName": "Waters",
"company": "Fuelton",
"employed": refreshCount%2 == 1
}
];
$http.post("https://httpbin.org/post", sampleData)
.success(function(data){
rootScope.myData = JSON.parse(data.data);
refreshCount++;
controllerScope.getPeopleButtonText = "Refresh " + refreshCount;
controllerScope.errorMessage = "";
})
.error(function() {
controllerScope.errorMessage = "An error has occurred."
});
};
this.clearPeople = function(rootScope, controllerScope) {
rootScope.myData = [];
controllerScope.getPeopleButtonText = "Get People";
}
}]);
Is there a better way to structure this code?
Another approach I have read about was to create a ViewService and expose the ViewService into the root scope.
EDIT Nov 19
I'm using an Angular Promise to handle the success/error cases of a service call in a controller, rather than inside the service. This allows me to move view updates into the controller. Is this the right place to keep the view updates?
this.getPeople = function() {
PersonService.getPeople()
.then(function(data) {
$scope.myData = JSON.parse(data);
controllerScope.getPeopleButtonText = "Refresh";
controllerScope.errorMessage = "";
}, function(error) {
controllerScope.errorMessage = "An error has occurred."
});
};
Here's an example plnkr
http://plnkr.co/edit/tzuSX3aAcUqpH5bM7cIa?p=preview

Never use $rootScope to store data
Use the MVC pattern if you like, so:
One view, has one controller, has as many services as you need.
Your view shows data which are in the $scope
Your Controller is getting the data from your PersonService
The PersonService (or just the API service) gets the data from a backend.
Best practices would be like this (simplyfied):
Api.js
angular
.module( 'api', [])
.service('Api', Api);
Api.$inject = ['$http'];
function Api($http) {
var baseUrl = '/api/url/';
function getPersons() {
return $http({
method: 'GET',
url: baseUrl + 'YOUR/PERSON/URL'
});
}
return {
getPersons: getPersons
}
}
PersonController.js
angular
.module('personApp')
.controller('PersonController', PersonController);
PersonController.$inject = ['$scope', '$state', 'Api'];
function PersonController($scope, $state, Api) {
$scope.getPersons = function() {
Api.getPersons().then(function(response) {
$scope.persons = response.data;
}, function(error) {
// error message
});
};
}
Persons.html
<div ng-controller="PersonController">
<div id="grid1" ui-grid="{ data: persons }" class="grid"></div>
<button ng-click="getPersons()"></button>
</div>
Summary
Your view displays the data which is inside the $scope
The view has a controller, which is there for just getting the data and storing it in the $scope, providing the functions for the buttons
Your services are delivering the data to the controller

Related

Use json object as variable in controller via ngResource

I fetch json data via ngResource angular, it is easy to use in view by using {{ }} but i don't know how to put these json objects to variable.
var workersServices = angular.module('workersServices', ['ngResource']);
workersServices.factory('Worker', ['$resource',
function($resource){
return $resource('workers/:workerId.json', {}, {
query: {method:'GET', params:{workerId:'workers'}, isArray:true}
});
}]);
var workersControllers = angular.module('workersControllers', []);
workersControllers.controller('costsCtrl', ['$scope','Worker', function($scope, Worker) {
$scope.workers = Worker.query();
HERE I WANT NAME PROPERTY AT THAT SCOPE :
**$scope.janeDoeName = workers[0].name; ??? IT DOESNT WORK**
}]);
JSON DATA workers.json
[
{
"id": "jane-doe",
"name": "Jane Doe",
"department": "sales",
"period": {
"start": "2015-12-14",
"finish": "2018-12-14",
"periodOfNotice": false
},
"paymentHour": 20,
"hours": 168
}]
I just want to put chosen property from that json to $scope and use it later in some functions.
You can try a callback function in the query:
var workersControllers = angular.module('workersControllers', []);
workersControllers.controller('costsCtrl', ['$scope','Worker', function($scope, Worker) {
$scope.workers = Worker.query(function(){
$scope.janeDoeName = $scope.workers[0].name;
});
}]);

How to display a list of item from server to view via Angular material?

I am working on a project, where I have a list of items present at backend. I have to get that list items via get request and display to my view as a list items. (User can select multiple entries from the list). I got the list items from server to my angular controller. For this project I am using Angular material design. How can I display these list items from controller to view via angular material element, which is able to select multiple entries from the list?
Here is a code example,
angular.module('myApp').factory('searchService', function($log, $http) {
return {
getTaxonomie: function() {
var promise = $http.get("http://espri-host179:8586/callrec/getTaxonomy")
.success(function(response) {
$log.debug("successfully got Taxonomie");
return response;
console.log(" i am from service");
})
.error(function(error) {
$log.error("searchService.getTaxonomie error:" + error);
return {};
});
return promise;
}
};
});
I have created a service to get data from server and now i have to add it to the controller and then display to my view. Right now my controller and view are empty because i don't know how to proceed further.
Any help would be appreciated, Thanks.
here's a basic example on how to iterate on data recieved from a factory:
javascript:
app.controller('MainCtrl', function($scope, dataFactory) {
dataFactory.getData().then(function(res) {
$scope.people = res.data;
})
});
app.factory('dataFactory', function($http) {
var vm = this;
vm.getData = function() {
return $http.get('data.json');
};
return vm;
});
html:
<div ng-repeat="person in people">
{{$index}}: {{person.name}} is {{person.age}} years old
</div>
data.json:
[
{ "name": "john", "age": 19 },
{ "name": "john2", "age": 20 },
{ "name": "john3", "age": 21 }
]
here's an example plnkr

Creating custom service in Angular using MeanJS

Still very new to MeanJS and Angular, but am trying to get a repeater to use a custom node service that i created
Here is the Angular Template
<section data-ng-controller="AppController">
<section data-ng-controller="GroupsController" data-ng-init="findMyItems()">
<div class="page-header">
<h1>My Groups</h1>
</div>
<div class="list-group">
<a data-ng-repeat="group in groups" data-ng-href="#!/groups/{{group._id}}" class="list-group-item">
<small class="pull-right" data-ng-bind="group.shortId"></small>
<h4 class="list-group-item-heading" data-ng-bind="group.name"></h4>
<small class="list-group-item-text">
Posted on
<span data-ng-bind="group.created | date:'medium'"></span>
by
<span data-ng-bind="group.user.displayName"></span>
</small>
</a>
</div>
<div class="alert alert-warning text-center" data-ng-hide="!groups.$resolved || groups.length">
No Groups yet, why don't you create one?
</div>
</section>
</section>
Here is an array of JSON objects returned from localhost:3000/users/me/groups
[
{
_id: "5407dd31594e810000af4fa0",
user: "5407c78f9ef3025bbf0440f7",
description: "Activating....",
__v: 0,
projects: [ ],
created: "2014-09-04T03:32:01.825Z",
shortId: "bkXtE746M",
name: "Wonder Twins"
},
{
_id: "5407dc49a34a610000af6896",
user: "5407c78f9ef3025bbf0440f7",
description: "Loved watching this one",
__v: 0,
projects: [ ],
created: "2014-09-04T03:28:09.480Z",
shortId: "WJejxZorTz",
name: "Fantastic Four"
},
{
_id: "5407d71839c7de000008cf6b",
user: "5407c78f9ef3025bbf0440f7",
description: "Great group",
__v: 0,
projects: [ ],
created: "2014-09-04T03:06:00.098Z",
shortId: "ZJfKDyN6f",
name: "Leaders of the New School"
}
]
Controller
'use strict';
// Groups controller
angular.module('groups').controller('GroupsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Groups', 'GroupsAPI',
function($scope, $stateParams, $location, Authentication, Groups, GroupsAPI ) {
$scope.authentication = Authentication;
$scope.findMyItems = function() {
GroupsAPI.getGroupsByCurrentUser()
.success(function (groups) {
$scope.groups = groups;
})
.error(function (error) {
$scope.status = 'Unable to load group data: ' + error.message;
});
};
}
]);
I'm not exactly sure what the service is doing in MeanJS
'use strict';
//Groups service used to communicate Groups REST endpoints
angular.module('groups').factory('Groups', ['$resource',
function($resource) {
return $resource('groups/:groupId', { groupId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
What I'd like to do is something like to do is something like bellow, but not sure if there is a better way
'use strict';
//Groups service used to communicate Groups REST endpoints
angular.module('groups').factory('Groups', ['$resource',
function($resource) {
return $resource('groups/:groupId', { groupId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
angular.module('groups')
.factory('GroupsAPI', ['$http', function($http) {
var GroupsAPI = {};
GroupsAPI.getGroupsByCurrentUser = function () {
return $http.get('users/me/groups');
};
return GroupsAPI;
}]);
Is there a better way of doing this the MeanJS way?
It's been a long time since you posted this, so you likely figured out a solution already, but for the sake of future readers I'll toss an answer in here.
If I'm understanding what you're trying to do, it looks like you are trying to create a custom factory that functions similar to the existing Groups factory (the one you mentioned you didn't know what it was doing). That's what I'll be answering...
To begin with, you'll want to read the Angular documentation on $resource: https://docs.angularjs.org/api/ngResource/service/$resource. This is what makes the Groups factory work.
To summarize, Angular's $resource allows you to make AJAX requests very easily, by allowing you to create a variable in your controller which has access to REST functions. So basically, you would do something like this:
// Groups controller
angular.module('groups').controller('GroupsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Groups', 'GroupsAPI',
function($scope, $stateParams, $location, Authentication, Groups, GroupsAPI ) {
$scope.authentication = Authentication;
// Since you've added 'Groups' as a dependency, you can now use this "resource" in a new variable.
var groups = new Groups({
// Set any object data you need here, or leave empty.
});
// Now that you have a new instance of your 'Groups' resource (i.e. 'groups'), you can use standard REST calls.
groups.get({
user: currentUser
}, function(results) {
// Do something with results here, e.g.
if(results) {
$scope.groups = results;
} else {
$scope.status = 'Unable to load group data.';
}
});
]);
Note: I haven't tested this code, but this is the idea.

Single Controller for multiple html section and data from ajax request angularjs

I'm trying to show two section of my html page with same json data, i don't want to wrap both in same controller as it is positioned in different areas. I have implemented that concept successfully by using local json data in "angular service" see the demo
<div ng-app="testApp">
<div ng-controller="nameCtrl">
Add New
Remove First
<ul id="first" class="navigation">
<li ng-repeat="myname in mynames">{{myname.name}}</li>
</ul>
</div>
<div>
Lot of things in between
</div>
<ul id="second" class="popup" ng-controller="nameCtrl">
<li ng-repeat="myname in mynames">{{myname.name}}</li>
</ul>
JS
var testApp = angular.module('testApp', []);
testApp.service('nameService', function($http) {
var me = this;
me.mynames = [
{
"name": "Funny1"
},
{
"name": "Funny2"
},
{
"name": "Funny3"
},
{
"name": "Funny4"
}
];
//How to do
/*this.getNavTools = function(){
return $http.get('http://localhost/data/name.json').then(function(result) {
me.mynames = result.mynames;
return result.data;
});
};*/
this.addName = function() {
me.mynames.push({
"name": "New Name"
});
};
this.removeName = function() {
me.mynames.pop();
};
});
testApp.controller('nameCtrl', function ($scope, nameService) {
$scope.mynames = nameService.mynames;
$scope.$watch(
function(){ return nameService },
function(newVal) {
$scope.mynames = newVal.mynames;
}
)
$scope.addName = function() {
nameService.addName();
}
$scope.removeName = function() {
nameService.removeName();
}
});
jsfiddle
Next thing i want to do is to make a http request to json file and load my two section with data, and if i add or remove it should reflect in both areas.
Any pointers or exisisitng demo will be much helpful.
Thanks
The reason why only one ngRepeat is updating is because they are bound to two different arrays.
How could it happen? It's because that you have called getNavTools() twice, and in each call, you have replaced mynames with a new array! Eventually, the addName() and removeName() are working on the last assigned array of mynames, so you're seeing the problem.
I have the fix for you:
testApp.service('nameService', function($http) {
var me = this;
me.mynames = []; // me.mynames should not be replaced by new result
this.getNavTools = function(){
return $http.post('/echo/json/', { data: data }).then(function(result) {
var myname_json = JSON.parse(result.config.data.data.json);
angular.copy(myname_json, me.mynames); // update mynames, not replace it
return me.mynames;
});
};
this.addName = function() {
me.mynames.push({
"name": "New Name"
});
};
this.removeName = function() {
me.mynames.pop();
};
});
testApp.controller('nameCtrl', function ($scope, nameService) {
// $scope.mynames = nameService.mynames; // remove, not needed
nameService.getNavTools().then(function() {
$scope.mynames = nameService.mynames;
});
/* Remove, not needed
$scope.$watch(
function(){ return nameService },
function(newVal) {
$scope.mynames = newVal.mynames;
}
);
*/
$scope.addName = function() {
nameService.addName();
};
$scope.removeName = function() {
nameService.removeName();
};
});
http://jsfiddle.net/z6fEf/9/
What you can do is to put the data in a parent scope (maybe in $rootScope) it will trigger the both views ,And you don't need to $watch here..
$rootScope.mynames = nameService.mynames;
See the jsFiddle

How to display JSON list data in angularjs

I am new to Angularjs and having trouble displaying data . i.e. Json array
This is the result of my rest service call:
{
"users": [{
"id": 1,
"firstname": "Naveen",
"lastname": "Dutt",
"email": "navee23ndutt12.vyas#gmail.com",
"telephone": "7829418456445355"
}]
}
And this is my controller:
app.controller('MyCtrl2', ['$scope', 'NFactory', function ($scope, NFactory) {
alert("here??");
$scope.bla = NFactory.query;
alert("here??" + $scope.bla);
NFactory.get({}, function (nFactory) {
$scope.allposts = nFactory.firstname;
})
}]);
This is my html:
<div>
<ul >
<li ng-repeat="user in bla"> {{ user.firstname }} </li>
</ul>
</div>
but it doesnt show anything on UI. what can be the problem? please suggest.
It happens because you call async task. I would wrap result with promise.
Here is basic simulation of async call:
Demo Fiddle
var app = angular.module('myModule', ['ngResource']);
app.controller('fessCntrl', function ($scope, Data) {
Data.query()
.then(function (result) {
console.log(result);
$scope.bla = result.users;
}, function (result) {
alert("Error: No data returned");
});
});
app.$inject = ['$scope', 'Data'];
app.factory('Data', ['$resource', '$q', function ($resource, $q) {
var data = {
"users": [{
"id": 1,
"firstname": "Naveen",
"lastname": "Dutt",
"email": "navee23ndutt12.vyas#gmail.com",
"telephone": "7829418456445355"
}]
};
//Actually we can use $resource
//var data = $resource('localhost/shfofx/PHP/Rest/alertLossDetails.php',
// {},
// { query: {method:'GET', params:{}}}
// );
var factory = {
query: function (selectedSubject) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
}]);
If $scope.bla in your case is
{"users":[{"id":1,"firstname":"Naveen","lastname":"Dutt","email":"navee23ndutt12.vyas#gmail.com","telephone":"7829418456445355"}]
then your template should look like this:
<ul >
<li ng-repeat="user in bla.users"> {{ user.firstname }} </li>
</ul>
Another way would be to change the code inside your Controller like this:
$scope.bla = NFactory.query.users;
and leave template as you have it.
If NFactory.query is string you need to parse it as JSON first.
$scope.bla=JSON.parse(NFactory.query);
and then
<ul >
<li ng-repeat="user in bla.users"> {{ user.firstname }} </li>
</ul>
Hope this will help...
Shouldn't it be a method call: NFactory.query() ?
Please show the NFactory source.
UPDATE: Try responding just array from server:
[{
"id": 1,
"firstname": "Naveen",
"lastname": "Dutt",
"email": "navee23ndutt12.vyas#gmail.com",
"telephone": "7829418456445355"
}]
and use NFactory.query()

Resources