Is there any way to do code grouping using partials in angularjs?
Reason --- I have a controller which contains too much code. This controller contains the code For several Methods and a lot of functionalities, it reduces the readability of the code. I want to keep controller name the same and do code grouping.
Ex:-
app.controller('MainController', function ($scope, router) {
$scope.Read = function() {
};
$scope.Write = function() {
};
$scope.Update = function() {
};
$scope.Delete = function() {
};
});
Partial:
app.controller('MainController', function ($scope, router) {
$scope.firstName = firstname;
$scope.middleName = middleName;
$scope.lastName = lastName;
});
Another Partial:
app.controller('MainController', function ($scope, router) {
$scope.Print = function() {
};
$scope.PrintPreviw = function() {
};
});
I need to implement it like this.
Is there any other way? yes please update..
Thanks
You could try to sort the code into logical chunks. after that, you could merge logical chunks into objects.
//Do NOT do this!
$scope.firstName = firstname;
$scope.middleName = middleName;
$scope.lastName = lastName;
//instead do this
var person = {
firstname: "name",
middleName: "mName",
lastName: "Lname"
}
//then in your view access them like this
{ { person.firstname } }
Also, you could move some code into services or factories. then use those methods inside of your controller.
//take things out of your controller and put then in a service or factory.
app.service('notePad', function () {
return {
Read: function (newState) {
return state += state;
},
Write: function (state) {
return state += state;
},
Update: function (state) {
state = state;
},
Delete: function () {
state = null;
}
};
});
//then in your controller access them like this
//Note you do not need everything on $scope if you are not going to use it in the view.
app.controller('MainController', function ($scope, router, notePad) {
$scope.Read = notePad.Read();
$scope.Write = notePad.Write();
$scope.Update = notePad.Update();
$scope.Delete = notePad.Delete();
});
If you need the functionality of a controller inside of a service you can still access scope and other controller properties like this.
NOTE: Make sure you create an onDestroy method to clean up any leftover variables.
//pass your scope to your service
app.controller('MainController', function ($scope, router, notePad) {
notePad.changeView($scope);
});
//munipulate your scope just like you would in a controller
app.service('notePad', function () {
function changeView(scope) {
scope.write = 'example';
}
});
//the result of the scope change in the service will show up in the view
{ { write } } == 'example'
Related
I have two REST web services which I have to call one by one. The first one return some data which I have to use for the second REST service call. The result of the second one, I need to provide it to my directive which should display the values.
I build with AngularJS a controller in this way:
app.controller('MyRestCtrl', [$scope, 'RestScope', function($scope, RestScope) {
RestScope.preGet().success(function(data) {
/* success of the first REST call and do some calculations with this data */
/* Question: I have to set the calculated data (data1 and data2) to the
RestScope provider, how can I do this, so that the second call
.get() has this data to make the request? */
RestScope.get().success(function(response) {
/* response has all the data which I need for my directive */
/* Question: How can I provide this data into my directive? */
});
})
}]);
And here is the provider:
app.provider('RestScope', function() {
this.data1 = null;
this.data2 = null;
this.setData1 = function(_data1) {
this.data1 = _data1;
}
this.setData2 = function(_data2) {
this.data2 = _data2;
}
this.$get = ['$http', '$log', function($http, $log) {
var _data1 = this.data1;
var _data2 = this.data2;
function get() {
return $http.get('http://www.test.com/' + _data1 + '/?param=' + _data2);
}
function preGet() {
return $http.get('http://www.test.com/getData/');
}
return {
get: get,
preGet: preGet
};
}];
});
And here is my directive:
app.directive('myDirective', function() {
return {
restrict: 'AEC',
replace: false,
templateUrl: 'path/to/my.html'
};
});
So the first thing is how to set inside of the preGet().success some data to the RestScope provider? And the second question if I get the data of the second call get().success how to provide it to my directive?
I have a function inside a directive that makes a query (and gets results, according to the console). The problem is that I can't seem to be able to store those results into a factory, and pass them to a controller.
This is the directive:
scope.getVersions = function(release) {
if (angular.isUndefined(release)) return;
musicInfoService.getReleaseVersions(release.id)
.success(function(data) {
dataService = data.versions;
console.log(dataService);
});
};
The console shows that dataService contains an array with the results.
Then, I try to store it into a factory:
app.factory('dataService', [function(){
return { items: [] };
}]);
And I call it in a controller:
function VersionController($scope, dataService) {
$scope.versions = dataService.items;
console.log($scope.versions);
}
But both items and $scope.versions come back an empty array. Did I miss something?
You should really use a backing field to store that data, and use setter and geter functions for writing and reading respectively:
app.factory('dataService', [function(){
var _items={};
return {
setItems:function(value){
_items=value;
},
getItems:function(){
return _items;
}
};
}]);
And for setting the data:
musicInfoService.getReleaseVersions(release.id)
.success(function(data) {
dataService.setItems(data.versions);
console.log(dataService);
});
and reading:
function VersionController($scope, dataService) {
$scope.versions = dataService.getItems();
console.log($scope.versions);
}
See demo plunk.
There's a misunderstanding of angular factories going on here. You're trying to set dataService = , which will never work.
As Mohammad mentioned, you need to have a variable set outside of your return value in the factory and the return value is basically an object with functions that allow you to manipulate your constant. So what you need is a getter "getItems()" for getting the items, and a setter "addItem(item)" for adding an item to your items array.
So you're never directly injecting your "items" into a controller, you're injecting a bunch of functions that can get or manipulate your "items".
scope.getVersions = function(release) {
if (angular.isUndefined(release)) return;
musicInfoService.getReleaseVersions(release.id)
.success(function(data) {
dataService.addItem(data.versions);
console.log(dataService.getItems());
});
};
app.factory('dataService', [function(){
var items = [];
return {
addItem: function(item) {
items.push(item);
},
getItems: function() {
return items;
}
};
}]);
function VersionController($scope, dataService) {
$scope.$watch(dataService.getItems, function(items) {
$scope.versions = items;
console.log($scope.versions);
});
}
I have an object representing a person:
function Person(_name) {
this.name = _name;
this.start = function() {
var that = this
$timeout( function sayHello() {
console.log(that.name);
$timeout(sayHello, 1000);
}, 1000);
}
}
Notice that is uses the angular $timeout service. Where should I put this so that I can declare people in my controller:
function Ctrl($scope) {
// How do I access Person so I can do this?
$scope.p1 = Person('nick');
$scope.p2 = Person('amy');
$scope.p1.start();
$scope.p2.start();
}
I can put the declaration in the controller body, and it works but that doesn't seen like good design. I'm pretty sure a value, or provider is specifically for this. But not sure how it would work given the dependency on $timeout.
You can create objects in a factory
var Person = (function (params) {
angular.extend(this, params);
return {
name: params.name,
};
});
Person.create = function create(params) {
return new Person(params);
};
myApp.factory('Person', function ($timeout) {
return Person;
});
Then in your controller you can inject the factory and create Person objects.
myApp.controller('HomeCtrl', function($scope, Person) {
$scope.person = Person.create({ name: 'Andy' });
});
I would make it a Service that returns a constructor.
var myModule = angular.module('myModule', []);
myModule.service('Person', function($timeout) {
// Actual person constructor defined once when
// the service is first instantiated
function Person(name) {
this.name = name;
this.start = function() {
var that = this
$timeout( function sayHello() {
console.log(that.name);
$timeout(sayHello, 1000);
}, 1000);
}
}
this.create = function (name) {
// Return a new instance
return new Person(name);
};
});
Note that you would use Person.create() to make instances in this case.
I want to watch angular factory variable from inside directive, and act upon change.
I must be missing something fundamental from Javascript, but can someone explain, why approach (1) using inline object works, and approach (2) using prototyping does not?
Does prototype somehow hide user variable scope from angular $watch?
How can i make this code more clean?
(1):
Plunkr demo
angular.module('testApp', [
])
.factory('myUser', [function () {
var userService = {};
var user = {id : Date.now()};
userService.get = function() {
return user;
};
userService.set = function(newUser) {
user = newUser;
};
return userService;
}])
.directive('userId',['myUser',function(myUser) {
return {
restrict : 'A',
link: function(scope, elm, attrs) {
scope.$watch(myUser.get, function(newUser) {
if(newUser) {
elm.text(newUser.id);
}
});
}
};
}])
.controller('ChangeCtrl', ['myUser', '$scope',function(myUser, $scope) {
$scope.change = function() {
myUser.set({id: Date.now()});
};
}]);
(2):
Plunkr demo
angular.module('testApp', [
])
.factory('myUser', [function () {
var user = {id : Date.now()};
var UserService = function(initial) {
this.user = initial;
}
UserService.prototype.get = function() {
return this.user;
};
UserService.prototype.set = function(newUser) {
this.user = newUser;
};
return new UserService(user);
}])
.directive('userId',['myUser',function(myUser) {
return {
restrict : 'A',
link: function(scope, elm, attrs) {
scope.$watch(myUser.get, function(newUser) {
//this watch does not fire
if(newUser) {
elm.text(newUser.id);
}
});
}
};
}])
.controller('ChangeCtrl', ['myUser', '$scope',function(myUser, $scope) {
$scope.change = function() {
myUser.set({id: Date.now()});
};
}]);
Case 1:
myUser.get function reference is called without a context (return user), and the user object is returned as a closure variable.
Case 2:
myUser.get function reference is called without a context (return this.user), and so this.user only just don't throw an error because you are not in "strict mode" where this is pointing to the window object, thus resulting in this.user being just undefined.
What you actually missed is the fact that giving myUser.get as a watcher check function is giving a reference to a function, which will not be applied to myUser as a context when used by the watcher.
As i remember angular watches only properties belonging to the object.
The watch function does this by checking the property with hasOwnProperty
I have a service which will make a call to the server and returns the data. I am binding service to a variable on scope.
Example:
Let the service be DataModelService
in the controller : $scope.data = DataModelService
in the view <div ng-repeat="value in data.persons">{{value.name}}</div>
My Code :
This is how my code looks like:
/**DataModelService**/
factory('DataModelService', [
'DataService',
function (DataService) {
var service;
service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
service.loadData(response.data);
});
},
loadData: function (responseData) {
service.persons = responseData.persons;
}
}
return service;
}
]);
/**DataService**/
factory('DataService', ['$http',
function ($http) {
return {
changePersonState: function (params) {
return $http.post("url", params);
}
}
}
]);
/**DataController**/
.controller('DataController', ['DataModelService',
function (DataModelService) {
$scope.data = DataModelService;
}
]);
/view/
<div ng-repeat = "person in data.persons" >{{person.name}} </div>
On the view I am doing a ng-repeat on a key in data i.e. ng-repeat="value in data.persons"
and also I have an option to change the state of person to active or inactive, so whenver i make a change to the state of the person, a call is sent to the server and data is set into the Service and as it is binded to the view, it should automatically update the data. But whats happening in my case, ng-repeat is not removing old data and instead it is appending new data to the old data.
For me its not good approach to write promise callback (then) into service. Because in your case, DataModelService returns data with some delay but not promise. And we don't know when.
So the way to make it work to add basic $timeout and fetch data from service by using other method.
So my suggestion is Demo
and your fixed example: Demo2
If we will take your example, it should be like:
JS
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function ($scope, DataModelService, $timeout) {
$scope.alertSwap = function () {
DataModelService.changeState('ff');
$timeout(function(){
$scope.data = DataModelService.getResponse();
}, 10);
}
});
fessmodule.$inject = ['$scope', 'Data', '$timeout'];
/**DataModelService**/
fessmodule.factory('DataModelService', [ 'DataService',function (DataService) {
var value = [];
var service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
value = response.persons;
});
},
getResponse : function(){
return value;
}
}
return service;
}
]);
/**DataService**/
fessmodule.factory('DataService', ['$q',function ($q) {
var data = { // dummy
persons: [{
name: "Bob"
}, {
name: "Mark"
}, {
name: "Kelly"
}]
};
var factory = {
changePersonState: function (selectedSubject) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
} //function
]);