Angular resource REST has no method '$save' - angularjs

I would like to interact with a REST API using $resource but when calling the save method I get has no method '$save' error. My code is inspired by the answer found on AngularJS $resource RESTful example
myapp.factory('Monitoring', function($resource) {
return $resource('http://localhost:8080/wepapp/network/v1/cronjobs/:id', { id: '#id' } );
});
Q1: What is the purpose of # in { id: '#id' }? I found it in most of the examples.
myapp.factory('MonitoringCRUDControllerService', ['Monitoring', function(Monitoring) {
return {
create: function(id, command, schedule) {
console.log("create");
console.log(command);
console.log(schedule);
Monitoring.id = id;
Monitoring.command = command;
Monitoring.schedule = schedule;
console.log(Monitoring);
Monitoring.$save();
}
}
}]);
The Monitoring object is correctly injected:
function Resource(value){
copy(value || {}, this);
}
Calling the $save failed with the error has no method '$save'.
Q2: What the purpose of $ before save?
Q3: What am I missing to make the save method work?

You need to create an instance of your Monitoring class like this (not tested):
var m = new Monitoring({id:id});
m.command = command;
m.schedule = schedule;
m.$save();
The documentation (http://docs.angularjs.org/api/ngResource.$resource) has a similar example:
var newCard = new CreditCard({number:'0123'});
newCard.name = "Mike Smith";
newCard.$save();
I asked the same question about the # sign a while ago: "at" sign in parameter names in resource definition. Basically # sign means that the value will be read from the object's property. Or as the same documentation says:
If the parameter value is prefixed with # then the value of that
parameter is extracted from the data object (useful for non-GET
operations).
The $ is not any special character, it is just a part of the method name.

Related

Get an object's name as the value of this

I am trying to understand the value of this at different points in a script. Questions similar to mine have been answered in this forum but those answers are considerably above my current learning level.
In my code experiments, I am using console.logs to return the this value. The value returned is always as expected, but the format of the returned value is inconsistent, which leads me to wonder why.
This code returns the expected Window object for the first 3 log commands to be executed but returns only the object literal for the 4th command, executed from the object's method.
var myName = {
name: "James",
sayName: function() {
console.log(this, 4);
console.log(this.name)
}
}
console.log(this, 1);
function myFunction() {
console.log(this, 2);
function nestFunction() {
console.log(this, 3);
myName.sayName();
}
nestFunction();
}
myFunction();
I have 3 questions: Why doesn't console.log return the name of the object? Is there a way to make it do so? Is there a simple way to do that other than console.log? Any help would be appreciated.
Ok I was going through your code to see what you specifically mean
here is the short explanation as to why THIS is different in some of the places
This keyword refers to the object it belongs to. Generally you used it to refer to the global window object .That's what is reflecting in your console log 1,2,3 .
Calling this in static javaScript object will return the javaScript object ,not the window object that is what is reflecting in the console.log(this,4).
So it gives you a way to call elements inside a static object .
Another way to understand this keyword is to look at constructors .The best example of the keyword
this
is inside a constructor function
var myObj = function(){
function myObj(ref)
{
this.name = "";
this.Item = "";
this.ref = ref;
this.speak();
}
myObj.prototype.speak =function()
{
this.name = 'James';
this.item = 'cheese';
console.log(this.ref)
//and the constuctor object
console.log(this)
}
return myObj;
}();
var e = new myObj('a Refrence string');
This should give you a basic understanding of how this works
here is more info to get you started Wschools.com

AngularJS how to update a JSON value with a dynamic key and an $http response?

I have this JSON example:
$scope.channels = {
"ch1": {
id: "ch1",
data: {}
},
"ch2": {
id: "ch2",
data: {}
}
};
QUE 1
How do I update the data: {} part with the dynamic key ?
something like:
for ( var c in $scope.channels ) {
$http.get(JSON_PATH + c + '.json').then(function(res){
// DOES NOT WORK
$scope.channels[c]["data"] = res.data;
// ALSO DOES NOT WORK
var section = $scope.channels[c];
section.data = res.data;
$scope.channels[c] = section;
});
}
The result of $scope.channels is now to have a new section called "data" instead of being under the key == "ch1" (i.e).
In addition, Sublime Text 3 also gives a warning which I'm not sure why? ( it's not like I'm using this or something:
181 don't make functions within a loop
QUE 2
I solved the above problem by actually create an external function and call it within the loop.
So I was wondering why the above code in Que1 doesn't work, while this does:
function load_data(id) {
$http.get(JSON_PATH + c + '.json').then(function(res){
var section = $scope.channels[c];
var section.data = res.data;
$scope.channels[c] = section; // WORK
});
}
for ( var c in $scope.channels ) {
load_data(c);
}
In Que 1 the for loop has continued it's cycle while the $http method is asyncronously processing. The "c" variable has lost it's original context and value. I believe it is destroyed once the for loop completes.
In Que 2, "c" is now "id", and has been passed in as a static value that will continue to be available to anything inside the function closure regardless of asyncronous activity. The function makes a reference to "c" and ceases to care whether the loop destroys it or not.
This has to do with function closures, and will need someone with a better understanding to explain it in detail.
You should change "c" to "id" in Que 2 though, inside your function.
Also, as a semi-related side note, if you are going to loop a series of $http calls, you might want to look up the $q.all documentation and read about how to build promise arrays where you can detect resolution of all calls rather than just individual calls. It can be quite useful.

Angular Translate - how to retrieve dynamic variable list

I have this in the translation json file:
{
"test_key" : "Var1: {{var1}} Var2: {{var2}} Var3: {{var3}}"
}
For this to work, I need to provide var1, var2, and var 3. For example:
$translate('test_key', { var1: 1, var2: 2, var3: 3 });
The issue now is that var1, var2, var3 could be any dynamic variables. What I need now is to get all the list of dynamic variables so I can provide whatever values it may need.
Ideally, this is the goal I am trying to achieve (pseudo code)
var dynamicVars = getDynamicVarList(); // I need this, but how?
dynamicVars.forEach(function (key) {
switch (key) {
case "var1":
return 1;
case "var2":
return 2;
case "var3":
return 3;
default:
return null;
}
});
If it is Pascal Precht translate, then you set JSON file in module options, before application init. It's rather not possible with standard mechanisms. It offer JSON, but when it is loaded, then it's hard to change something, without changing source code of angular translate module.
If the reason you want this is to have many languages, then you can set many languages codes in $translate.
Another solution is to load JSON from server, which performs operations on var1, var2, var3 and hence returns static json, but you can do $http calls with commands to change variables in switch statement.
It looks somehow linguistic approach, Java is good for this. Grails may be fine framework for returning REST services.
Again, to restate the problem, the issue is that you do not know ahead of time which dynamic variables are to be used.
I solved the issue by using a customer interpolator.
So when you do
{{'testkey'|translate}}
and your lang.json has:
"testkey" :"this is number {{variable1}}"
It will get resolved to
this is number 1
Code:
app.factory('customTranslateInterpolator',
["$interpolate",
function ($interpolate) {
var $locale;
var customTranslateInterpolator = {};
/**
* This will be your custom dynamic vars resolution method
*/
var resolveExpressions = function (expressions) {
var values = {};
expressions.forEach(function (key) {
values[key] = resolveVariable(key);
});
return values;
}
/**
* The actual method for key:value mapping
*/
var resolveVariable = function(key) {
var retVal;
switch (key) {
case "variable1":
retVal = 1;
break;
default:
retVal = "";
}
return retVal;
}
customTranslateInterpolator.setLocale = function (locale) {
$locale = locale;
}
customTranslateInterpolator.getInterpolationIdentifier = function () {
return 'custom';
},
/**
* Custom interpolate
* interpolateParams will overwrite resolve expressions. This will allow developers
* to pass values to the translate directives or by using $translate service.
*
* #param {string} string the string retrieved from the language json file
* #param {object} interpolateParams the {key:value} object passed to the angular-translate features.
*/
customTranslateInterpolator.interpolate = function (string, interpolateParams) {
var result;
interpolateParams = interpolateParams || {
};
// Retrieve expressions and resolve them
var interpolatedString = $interpolate(string);
var resolvedExpressions = resolveExpressions(interpolatedString.expressions);
// Merge interpolateParams onto resolvedExpressions so that interpolateParams overwrites resolvedExpressions
angular.extend(resolvedExpressions, interpolateParams);
result = interpolatedString(resolvedExpressions);
return result;
}
return customTranslateInterpolator;
}]);
make sure you let angular-translate know you are using a custom interpolator
$translateProvider.useInterpolation('customTranslateInterpolator');
Note that you can still provide your own translate-values, and this will override whatever you have in resolveVariable()
So if you do
{{'testkey' | translate:"{variable1:'2'}"}}
It will resolve to
this is number 2
Hope this helps others.
-Lucky M.

Re-use array collection on multiple pages

I currently have 2 pages, page1.php and page2.php, each of the pages uses a controller that completes its own functions etc.
However there are tabs within the pages that are exactly the same that gets a promise from a factory within the module. The lists are exactly the same except for querying on different IDs. For example both controllers have this:
pageListFactory.getData().then(function (result) {
$scope.BasicItems = result; $scope.basicItemsList = [];
angular.forEach($scope.BasicItems, function (BasicItem) {
angular.forEach(BasicItem['SomeInnerArray'], function (BasicSomeInnerItem) {
if (BasicSomeInnerItem == VARIABLE_THAT_CHANGES) {
$scope.basicItemsList.push({
ID: BasicItem.ID, Title: BasicItem.Title
});
}
});
});
});
So this code is used, and the VARIABLE_THAT_CHANGES is just what changes each time. However as I said it is used on multiple pages, is there a way to create just one function call and then each page just can call a specific bit and send the variable with it?
I tried using $rootScope but of course this just clogs and slows, and I'm not exactly happy on constantly using $rootScope to pass the $scope.basicItemsList around as the list could get quite big.
So is there any way to reuse this code without just copying and pasting it into each controller?
Sure you can re-use it...
Convert the factory to a service, its basically a name change, create a local variable to store the data, update the data on first call, and then grab the data if it exists on the second call.
.service('myService', ... stuff ... { // I suggest using a service, as I don't know if a factory would act as a singleton
var myData = null;
return {
getData: function(){
if(myData != null)
return myData; // returns data
else {
return $http()... // ajax call returns promise
}
},
setData: function(dataToSet){
myData = dataToSet;
}
}
Then your controllers:
//controller 1
var promiseOrData = pageListFactory.getData();
if(promiseOrData instanceOf Array){ // or whatever data you expect
$scope.BasicItems = promiseOrData;
....
}
else { // should be a promise
promiseOrData.then(function (result) {
pageListFactory.setData(result); // set the data once you get it.
$scope.BasicItems = result; $scope.basicItemsList = [];
....
}
}
In controller 2 you only need to get the data as the returned data will be an array, not a promise
On top of all this, write a directive which will process the data when you pass it along, then you can pass the variableThatChanges and have the directive take care of it.
Use services and write the function in that service and pass the variable VARIABLE_THAT_CHANGES into it. By this you can reuse the code.

Calculated property on shared service across multiple controllers

I'm sharing a service across multiple controllers. I've made this simplified fiddle to illustrate it: http://jsfiddle.net/ziaxdk/FFgpX/
app.service("common", function() {
var first = 1, second = 2;
return {
first: first,
second: second,
// {{model.first+model.second}} calculate this down here??
calc: function() { return first + second; } // This line is not watched
}
});
How can I create calculated rules/properties on the service object so they get reflected to the view?
Regards,
Kenneth
It is not really AngularJS-specific problem it is how closures work in JavaScript for primitive types. Basically when you've got a closure over a primitive type you are getting a copy of the original values instead of a reference to them. You are breaking the link. So in your code you've been changing different variable values then ones used to do calculation.
You could modify your service as follows:
app.service("common", function() {
return {
first: 1,
second: 2,
calc: function() { return this.first + this.second; }
}
});
And your code becomes operational.
Here is a working jsfiddle: http://jsfiddle.net/e3nzY/2/

Resources