How to access a variable inside an anguljarjs service from a function? - javascript

I have an angularjs service, that holds a model property for the frontend binding.
I also want to create a function that processes some input data and updates the model accordingly:
angular.module('test').service('testService', testService);
function testService() {
return {
model: [
mylist = null
],
setMyList: setMyList
};
function setMyList(data) {
//process data
mylist = data; //error: "model is not defined"
}
}
from any controller:
testService.setMyList(data);
Problem: the function cannot see the model. Why, and how could I change this?

I solved it as follows:
var model: {
mylist = null
};
return {
model: model,
setMyList: setMyList
}
function setMyList(data)...

Related

Get the value of a local variable into the controller in AngularJS

I have a JS file containing a controller and other functions structured like this:
class RandomCtrl {
constructor(randomService) {
this.randomService = randomService;
...
}
$onInit() {
getData.call(null, this);
}
...
}
function getData(RandomCtrl) {
...
}
function getChart(data) {
if (!data) {
return;
}
const chartOptions = getWeekHourlyOptions(data);
const allCols = [].concat(chartOptions.dataColumns);
allCols.push(["x"].concat(_.map(chartOptions.xAxis, element => moment(element).valueOf())));
const xVals = xAxisValues(chartOptions.xAxis);
...
}
...
RandomCtrl.$inject = ['randomService'];
export const Random = {
bindings: {
data: '<',
siteNames: '<'
},
templateUrl: randomPageHtml,
controller: RandomCtrl
};
I want to get the value of allCols from getChart() into the Controller.
I've tried to add it in $onInit like this.allCols = getData.allCols but it doesn't work. Probably not the right way.
Any solution to this?
Declare allCols as a global variable and populate the data in getChart()
send allCols in getChart() as return value so that whenever this method is called the return value can be stored into another variable and can be consumed

Two-way databind on a forEach?

I have an object of products. The products i get from a resource (Product), store in a factory (productsStore), and iterate through in a controller.
In another controller, i want to either empty of refresh products via productsStore.empty(); or productsStore.get();. But either of them does nothing. Meaning my forEach, below, is not being run again, and the list not updated.
What am i doing wrong?
Controller:
vm.products = productsStore.get();
vm.products.$promise.then(function (data) {
angular.forEach(vm.products, function (child) {
//. some code
)};
)};
Factory:
myApp.factory('productsStore', function ($http, $q, Product) {
var products = "";
var get = function () {
return products = Product.query();
};
var empty = function () {
return products = {};
};
// Bind products
products = get();
return {
get: get,
empty: empty
};
});
Resource:
myApp.factory('Product', function ($resource) {
return $resource('http://api.com/api/products/:id', { id: '#id' }, {
update: {
method: 'PUT'
}
});
});
try to loop through the data you get after the promise is resolved, otherwise it's a rather useless variable.
angular.forEach(data, function(child) {
//...do something with the child
});
Also, you have a typo, that I'm not sure you have in your actual code. In your controller, end of block should be }) and not )}

Angular.js share controller methods

I am working on a CMS that I originally was using Knockout but I decided to try Angular because it like more of its functionality. In the CMS, one of the sections will be 'Users'. It has a table that allows the headers to be clicked to sort the data. The controller is below:
userControllers.controller('UserListControl', ['$scope', 'User',
function($scope, User) {
$scope.users = User.query();
$scope.columns = [
{ 'field': 'last', 'label': 'Last Name' },
{ 'field': 'first', 'label': 'First Name' },
{ 'field': 'username', 'label': 'Username' },
{ 'field': 'email', 'label': 'Email' },
];
$scope.orderProp = 'last';
$scope.orderDirection = false;
$scope.tableSort = function(field) {
if ($scope.orderProp === field) {
$scope.orderDirection = !$scope.orderDirection;
}
$scope.orderProp = field;
};
$scope.tableSortClass = function(field) {
if ($scope.orderProp === field) {
if ($scope.orderDirection) {
return 'sortDesc';
}
return 'sortAsc';
}
};
}]);
It is part of my adminApp that I created. Since there will be other sections that will also use the table sort properties (orderProp, orderDirection) and methods (tableSort, tableSortClass), is there a place I can put these methods so my eventual recordsController will also have access to them?
OK, so I am trying to create it using a service and factory function. This is all new to me so I am not completely sure what I am doing but here is what I have:
adminServices.factory('TableSort', [
function() {
var orderProp = 'id';
var orderDirection = false;
function sort(field) {
alert('test');
if (orderProp === field) {
orderDirection = !orderDirection;
}
orderProp = field;
}
function sortClass(field) {
if (orderProp === field) {
if (orderDirection) {
return 'sortDesc';
}
return 'sortAsc';
}
}
}]);
I was hoping to access them in my html using something like ng-click="TableSort.sort(field)" but it doesn't work as it is right now.
As stated above in the other posts, you can create a service that you can inject into various controllers to "share" the code.
Below is a full example:
myApp.service('myService', function myService() {
return {
someVar: "Value",
augmentName: function(name){
return "Sir " + name;
}
}
});
This first piece is the service. I've defined a "myService" and given it one function "augmentName" Now you can inject the myService and access the augment name function.
myApp.controller('testCtrl', function ($scope, myService) {
$scope.testFunction = function(name){
console.log(myFunction.someVar); //This will access the service created variable
return myService.augmentName(name);
}
}
The controller injects the service and then calls it within one of its functions.
Now your HTML code should have access to the controller if you have defined an ng-controller with "testCtrl" or if you have put testCtrl as the controller in your router.
You can now call ng-model="testFunction(someName)" and it will resolve as expected.
Hope that helps. Let me know if you want me to go into greater depth
If you are still trying to figure out how everything in angular works, the angular phone cat tutorial helped me allot when I started out. I'd recommend donating an hour or so into playing with it.
Also, I highly recommend experimenting as early as possible with yeoman/angular generator, this will force you to use angular "the angular way" and can really help you with getting your project set up correctly.
You can use a Service or a Factory to hold these common methods. Additionally, you could use the $rootScope.
You can create a service and put all those properties and method in it. Here is an example for the same:
userControllers.service('UserListControl', function() {
var orderProp = 'last';
var orderDirection = false;
return {
tableSort : function(field) {
if (orderProp === field) {
orderDirection = !orderDirection;
}
orderProp = field;
};
tableSortClass: function(field) {
if (orderProp === field) {
if (orderDirection) {
return 'sortDesc';
}
return 'sortAsc';
}
};
}
});

How to query and extract from server response in Angular

I want to create a find method that loops through an array returned by the $resource service in Angular.
If I have a service like so:
'use strict';
angular.module('adminApp').factory('ProductType', function($resource) {
var ProductType;
ProductType = $resource('http://localhost:3000/api/v1/product_types/:id.json', {
id: '#id'
}, {
update: {
method: 'PUT'
}
});
ProductType.find = function(typeName){
var types = this.query(),
typeObject = {},
self = this;
for(type in types) {
var result = types[type],
resultName = self.normalizeName(result.name),
if(typeName === resultName) {
typeObject = result;
}
}
return typeObject;
};
return ProductType;
});
I tried wrapping it all in a function and returning the function thinking it had something to do with it being async and I also tried nesting a callback in the query method but that just allowed me to modify the response and not actually return anything differently.
When I try and set the return value to $scope in the controller I get a blank object
The this.query() method would return an array which might not be filled until the this.query() method has got its results back from the server. You will need to do something like this to wait until the call to the server has completed. As this is sort of async you will need to return a promise from this method that is resolved when the initial query has completed and you have searched the results.
'use strict';
angular.module('adminApp').factory('ProductType', [
'$q',
'$resource',
function($q, $resource) {
var ProductType;
ProductType = $resource('http://localhost:3000/api/v1/product_types/:id.json', {
id: '#id'
}, {
update: {
method: 'PUT'
}
});
ProductType.find = function(typeName) {
var defer = $q.defer(),
types = this.query(),
self = this;
types.$promise.then(function () {
var result,
resultName,
typeObject,
type;
for(type in types) {
result = types[type];
resultName = self.normalizeName(result.name);
if(typeName === resultName) {
typeObject = result;
break;
}
}
defer.resolve(typeObject);
}, function (err) {
// the called failed
defer.reject(err);
})
return defer.promise;
};
return ProductType;
}]);
Taken from the angular docs https://docs.angularjs.org/api/ngResource/service/$resource
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data.

Data flow issue with AngularJS

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);
});
}

Categories