AngularJS $resource update/ PUT operation? - angularjs

I'm confused as to how exactly to update a resource using $save. I've read the angular resource documentation and looked at other posts on stack overflow but I cannot seem to perform an update operation on an existing object.
For example, I have an event object and I want to update its name and location properties. I have the start of a function that correctly takes in the eventId of a singular event.
Here is the function so far:
eventService.updateEvent = function (eventId, eventName, eventLocation) {
// Defines the resource (WORKS)
var Event = $resource('/api/events/:id/', {id:'#_id'});
// Gets the event we're talking about (WORKS)
var event = Event.get({'id': eventId});
// TODO update event
};
How do i successfully update this resource?

Figured it out!
When I defined the resource, I defined the PUT operation as a custom method called 'update'.
I called get on that resource and looked up a particular object by ID.
Using a promise, I was able to update the resource using the 'update method' if the object was found, else throw an error.
eventService.updateEvent = function (eventId,eventName,eventLocation) {
// Define the event resource, adding an update method
var Event = $resource('/api/events/:id/', {id:'#_id'},
{
update:
{
method: 'PUT'
}
});
// Use get method to get the specific object by ID
// If object found, update. Else throw error
Event.get({'id': eventId}).$promise.then(function(res) {
// Success (object was found)
// Set event equal to the response
var e = res;
// Pass in the information that needs to be updated
e.name = eventName;
e.location = eventLocation;
// Update the resource using the custom method we created
Event.update(e)
}, function(errResponse) {
// Failure, throw error (object not found)
alert('event not found');
});
};

Related

Find Object Array and its Properties from Ajax Post Request

I'm sending an AJAX request to an internal PHP and receiving back an object. The object has properties of "data" and "status", yet when I try to access them, it does not return anything. How can I show each property separately?
For reference, the returned obj array is:
{"data:[{"tagId":"8787","tagDescription":"001","tagMin":"0","tagMax":"100"},{"tagId":"8729","tagDescription":"1","tagMin":"44","tagMax":"555"}]
function GetAll() {
var PostRequest ={};
PostRequest['tagId']= 'all';
$.post('php here',PostRequest,ShowAllTags);
}
function ShowAllTags( responseData, responseStatus ) {
console.log(responseStatus);
var tagData = {};
tagData = responseData;
console.log(tagData['data']);
}
So according to the above comment mention by me, The problem is with json object, in response.
So first of all fix that,
Generic solution of this problem will be;
var obj = [{"tagId":"8787","tagDescription":"001","tagMin":"0","tagMax":"100"},{"tagId":"8729","tagDescription":"1","tagMin":"44","tagMax":"555"}];
obj.forEach(function(value, index){console.log(value.tagId)});
This might help, how to get value of each property

Breeze - constructor not being invoked

I'm building a new Ng 1 project using Breeze. I need to add client-side properties to some entities. I added a constructor, but it does not get called. I added a post initializer, it is not called either.
// a convention can self-register as the default
breeze.NamingConvention.camelCase.setAsDefault();
// create a manager to execute queries
service.manager = new breeze.EntityManager("/api/pts");
// access to the manager's store to add custom client-side properties ..
service.metastore = service.manager.metadataStore;
// entities with client-side properties ..
service.metastore.registerEntityTypeCtor('PtsWine__Pts_BreezeModel', PtsWine, ptsWineInitializer);
var PtsWine = function () {
debugger;
this.uiDayUid = 0;
}
var ptsWineInitializer = function (pw) {
debugger;
pw.uiDayUid = 0;
}
var query = new service.EntityQuery().from("Wines");
return service.manager.executeQuery(query)
.then(function (d) {
debugger;
/// ??? examining d.results shows 40 PtsWine__Pts_BreezeModel entities but
/// constructor and initializer above were never invoked .. ???
})
.fail(function (response) {
toastr.error("Server Error: failed to retrieve listing.")
});
The initialization sequence does not seem correct to me. At the time registerEntityTypeCtor is executed PtsWine and ptsWineInitializer are undefined. Remember javascript hoisting concept? https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
You need to define the variable before calling registerEntityTypeCtor.

react js / superagent / file dropzone

I have a comments widget, in React js (jsx), and I'm using React Dropzone and uploading the dropped files to the server, using superagent.
I need to get the file object (containing my app's file id,etc) returned from my app, and associate them with the comment that the user will submit. I am attempting to assign the file objects to a state variable, 'attachments'. Because of the async nature of superagent, I think, I am actually populating my state variable with an empty array.
I have tried to use a callback, but got an 'undefined' error.
Here is the code:
onDrop: function (newFiles) {
newFiles.forEach((file)=>
{
this.setState({files: this.state.files.concat(file)});
})
var attachments = [];
var req = request.post('/attachments/create');
req.set('Accept', 'application/json');
newFiles.forEach((file)=> {
req.attach('img_attach', file);
req.field('filename', file.name);
req.field('itemType', 'comment');
req.field('itemId', false);
req.end(function(err,res){
var json = $.parseJSON(res.text);
attachments.push(json);
attIds.push(json.id);
});
});
attachments.forEach((file)=>
{
this.setState({
attachments:this.state.attachments.concat([file])});
});
},
Here is the callback attempt which returns "Cannot read property 'setState' of undefined":
function fileAttach(err,res)
{
var json = $.parseJSON(res.text);
this.setState({attachments:this.state.attachments.concat([json])});
}
For the callback, instead of this
req.end(function(err,res){
var json = $.parseJSON(res.text);
attachments.push(json);
attIds.push(json.id);
});
I use this
req.end(fileAttach);
So, one possibility is that I'm looking for a 'context' option, similar to jquery, that allows me to use 'this' in the callback.
So, you were on the right track for the first issue I see. You need to bind the context to that function. It's already been answered by LodeRunner28 in the comments, but you'd do:
req.end(fileAttach.bind(this))
If you're not familiar, Function.prototype.bind allows you to manually force a context variable for any function. It's incredibly handy, and it means you never have to rely on the library (eg. jQuery) to provide a context arg, you can just specify it yourself :)
The bigger issue I see is the way you're using SuperAgent. I believe you're actually sending a whole bunch of requests; calling .end triggers SuperAgent to make the request, and you're doing it inside the forEach loop.
I'm not super familiar with SuperAgent, but I believe you can just do:
newFiles.forEach( file => {
req.attach('img_attach', file);
req.field('filename', file.name);
req.field('itemType', 'comment');
req.field('itemId', false);
});
req.end(fileAttach.bind(this));

Angular $resource and use of Interceptor to check response/error/callback

Last few days I am working to invoke REST services and track the response, error, callback etc. I have gone through most of the posting however due to my limited understanding on Angular seems like I am not able to understand it. Following is my problem and understanding I got so far.
I am using Project.$update() service which returns only "project_id". This server doesn't return complete data again. Following is line of few line of code to share here.
//create Project factory
app.factory('Project', function ($resource) {
return $resource('/api/projects/:projectid',
{projectid:'#id'},
{update: {method:'PUT', isArray:false}}
);
});
Following is code in directive I am using to update/create project.
//save project
scope.saveProject = function (project) {
//update modified by field
project.modifiedby = scope.user._id;
//change to view mode
scope.projectView = 1;
//call server to save the data
if (project._id == undefined || project._id == "") {
//Call server to create new and update projectID
project._id = project.$save()._id;
}
else {
//Call server to update the project data
project.$update({ projectid: project._id });
}
};
Following is service response for both save() and update().
{"_id":"52223481e4b0c4d1a050c25e"}
Problem here is; "project" object value is replaced by new response returned by server having only project_id and other fields are replaced.
I was going through detailed documentation on $resource however I am not able to grasp it. It will be great to get some guidance here to write code to detect error, response, callback.
You can replace the original object by the one returned from the server in your success callback like this:
//save project
scope.saveProject = function (project) {
//update modified by field
project.modifiedby = scope.user._id;
//change to view mode
scope.projectView = 1;
//call server to save the data
if (project._id == undefined || project._id == "") {
//Call server to create new and update projectID
project.$save(function(updatedProject, headers){
// Replace project by project returned by server
project = updatedProject;
});
}
else {
//Call server to update the project data
project.$update(function(updatedProject, headers){
// Replace project by project returned by server
project = updatedProject;
});
}
};
That will replace the original object by the one returned by the server as soon as the server response is received.
If your callback is identical for the $save and $update methods, you can further simplify your code like this:
//save project
scope.saveProject = function (project) {
//update modified by field
project.modifiedby = scope.user._id;
//change to view mode
scope.projectView = 1;
var action = (angular.isDefined(project._id)) ? '$update' : '$save';
//call server to save the data
project[action](function(updatedProject, headers){
// Replace project by project returned by server
project = updatedProject;
});
};
Hope that helps!
As per suggestion made by jvandemo and BoxerBucks; I have used following approach for save/update by passing the callback method with copy of original data. However still I am looking for central approach to take care of error/success status. Please suggest.
//save project metadta
scope.saveProjectMetadta = function (project) {
//update modified by field
project.modifiedby = scope.user._id;
//change to view mode
scope.projectView = 1;
//keep original data to pass into callback
var originalProjectObject = angular.copy(project);
//call server to save the data
if (project._id == undefined || project._id == "") {
//Call server to create new and update projectID
project.$save(originalProjectObject, function (projectResponse) {
originalProjectObject._id = projectResponse._id;
//update scope
scope.project = originalProjectObject;
//invoke method to update controller project object state
scope.updateProjectScope(scope.project);
});
}
else {
//Call server to update the project data
project.$update({ projectid: project._id }, function (projectResponse) {
originalProjectObject._id = projectResponse._id;
//update scope
scope.project = originalProjectObject;
//invoke method to update controller project object state
scope.updateProjectScope(scope.project);
},originalProjectObject);
}
};

why does backbone think I'm treating an object like a function?

Adding Backbone to a Rails app, I created a post model inside an app namespace like this
var app = {
this.models.post = new app.Models.Post();
In the router, I created the following route
"posts/:id": "postDetails"
When I navigate to /posts/4, I'm getting an Uncaught TypeError: object is not a function error when I try to call fetch on the model like this
postDetails: function (id) {
console.log(id);
var post = new app.models.post({id: id});
this.post.fetch({
success: function (data) {
$('#content').html(new PostView({model: data}).render().el);
}
});
}
According to the Backbone docs http://backbonejs.org/#Model-fetch, I should be able to call fetch on a model to retrieve the data from the server. Why does Backbone think I'm treating an object like a function?
You're doing this:
this.models.post = new app.Models.Post();
to, presumably, set app.models.post to an instance of the app.Models.Post model. Then you try to do this:
var post = new app.models.post({id: id});
But you can only use the new operator on a function:
new constructor[([arguments])]
Parameters
constructor
A function that specifies the type of the object instance.
You probably want to say:
var post = new app.Models.Post({ id: id });
or something similar.
The problem is you've declared post as a local variable var post, but then tried to access it as a member this.post. You need either this:
this.post = new app.models.post({id: id});
this.post.fetch({ ...
Or this:
var post = new app.models.post({id: id});
post.fetch({ ...
(The difference being that a local variable var post is declared in transient scope and thrown away after postDetails completes; while instance variable this.post gets added to the Router object and will typically live for the whole lifetime of the application.)

Resources