after I change to Backbone-Relational my model stopped to work when I call destroy().. I have to ensure that when it removes success on server there will be no more id at client side, so then when I try to save it again my model wont request PUT (update) - throws Record Not Found on server side.
Coffeescript side
save: ->
if isBlank #model.get("text")
#model.destroy() # after success it still with same attributes including id!!
else
#model.save()
Rails side
def destroy
#note = Note.find(params[:id])
#note.destroy
respond_with #note # callback is empty
end
Bug from Backbone-Relational perhaps? Does Backbone.js update id after destroy?
Backbone does not look like it modifies the Model on destruction in any way. Except removing it from its collection if any.
Check the code
What it does is triggering the event destroy so you easily can listen this event and do whatever you think is the proper behavior in destruction:
// code simplified and no tested
var MyModel = Backbone.Model.extend({
initialize: function(){
this.on( "destroy", this.afterDestroy, this );
},
afterDestroy: function(){
this.set( "id", null );
}
});
Related
I am using sockets to pipe data to my project with a node server in the backend. I can configure my store correctly, but when I do the following:
class Store {
#observable
socketData = {};
constructor() {
this.socket = io("localhost:5000");
this.socket.on("event", function(data) {
this.socketData = data;
});
}
}
when I console.log(this.socketData) the data, it prints out a proxy instead of the JSON data I passed through from the socket. When I console.log(data) in the constructor, it prints out the object. Is there a reason why my data prints out as a proxy? Or is this a bad way to setup the observable with sockets?
MobX replaces your original data object with a proxy to be able to detect property access and modification.
Most of the time this is completely transparent and you don't need to be aware you are dealing with a proxy, but if you really need a plain JavaScript object, you can use mobx.toJS:
console.log(mobx.toJS(this.socketData))
Additionally, in your constructor you might want to change function(data) {...} to an arrow function data => {...} to make sure this refers to your store in the function body.
I would like to retrieve the id of a newly created record using javascript when I click on save button and just before redirecting page.
Do you have any idea please ?
Thank you !
One way to do this in Sugar 7 would be by overriding the CreateView.
Here an example of a CustomCreateView that outputs the new id in an alert-message after a new Account was successfully created, but before Sugar gets to react to the created record.
custom/modules/Accounts/clients/base/views/create/create.js:
({
extendsFrom: 'CreateView',
// This initialize function override does nothing except log to console,
// so that you can see that your custom view has been loaded.
// You can remove this function entirely. Sugar will default to CreateView's initialize then.
initialize: function(options) {
this._super('initialize', [options]);
console.log('Custom create view initialized.');
},
// saveModel is the function used to save the new record, let's override it.
// Parameters 'success' and 'error' are functions/callbacks.
// (based on clients/base/views/create/create.js)
saveModel: function(success, error) {
// Let's inject our own code into the success callback.
var custom_success = function() {
// Execute our custom code and forward all callback arguments, in case you want to use them.
this.customCodeOnCreate(arguments)
// Execute the original callback (which will show the message and redirect etc.)
success(arguments);
};
// Make sure that the "this" variable will be set to _this_ view when our custom function is called via callback.
custom_success = _.bind(custom_success , this);
// Let's call the original saveModel with our custom callback.
this._super('saveModel', [custom_success, error]);
},
// our custom code
customCodeOnCreate: function() {
console.log('customCodeOnCreate() called with these arguments:', arguments);
// Retrieve the id of the model.
var new_id = this.model.get('id');
// do something with id
if (!_.isEmpty(new_id)) {
alert('new id: ' + new_id);
}
}
})
I tested this with the Accounts module of Sugar 7.7.2.1, but it should be possible to implement this for all other sidecar modules within Sugar.
However, this will not work for modules in backward-compatibility mode (those with #bwc in their URL).
Note: If the module in question already has its own Base<ModuleName>CreateView, you probably should extend from <ModuleName>CreateView (no Base) instead of from the default CreateView.
Be aware that this code has a small chance of breaking during Sugar upgrades, e.g. if the default CreateView code receives changes in the saveModel function definition.
Also, if you want to do some further reading on extending views, there is an SugarCRM dev blog post about this topic: https://developer.sugarcrm.com/2014/05/28/extending-view-javascript-in-sugarcrm-7/
I resolved this by using logic hook (after save), for your information, I am using Sugar 6.5 no matter the version of suitecrm.
Thank you !
I've got two models defined in my Component.js. One is a list of all contacts and the other is only the logged in contact. Now i want to check in my controller if the logged in contact is already existing in the list of all contacts. I compare the registrationToken from the list agains the token from the logged in contact. But when i loop through the list the length is 0 because of asynchronous communication.
I saw the attachRequestCompleted function but now i got another problem... the onInit-function is already finished when my attach-function is fill my view-Model..
onInit : function(){
var gLocalContact = sap.ui.getCore().getModel("gLocalContact");
var gRemoteContacts = sap.ui.getCore().getModel("gRemoteContacts");
gRemoteContacts.attachRequestCompleted( function() {
... if ... setProperty to gLocalContact.getProperty("/registrationToken")...
console.log("I should be the first log to get the data in view");
});
console.log("I should be the second log!");
this.getView().setModel(gLocalContact, "localContact");
}
The first log in the attach-function should be first because there i define some data to gLocalContact which i need in my view. Another problem is that i have no access to my gLocalContact variable....
This is a little bit ugly because SAPUI5 does not support promises. So inside your view you don't know if the requestCompleted event will be fired or if the data has already been loaded. There are some solutions comming to my mind:
Attach the requestCompleted eventhandler in your component before you call loadData(). Then you can be shure that you will get the event.
You would have to build your view to handle an empty gLocalContact model though. But as soon as the model is populated with data the bindings will update the view.
Put the remaining stuff of your onInit() into your eventhander. To be sure to get the event do a check if there is already data in your model, and if so call your eventhandler manually to have it run at least once.
Use jQuerys Promises to synchronize. This allows you to wait for the second model too:
onInit : function(){
var gLocalContact = sap.ui.getCore().getModel("gLocalContact");
var gRemoteContacts = sap.ui.getCore().getModel("gRemoteContacts");
console.log("Wait some seconds for the data...");
var localContactPromise = this.getPromise(gLocalContact, "/origin");
localContactPromise.done(function() {
//same code as before but this time you can be shure its called.
//... if ... setProperty to
//gLocalContact.getProperty("/registrationToken")...
console.log("I should be the first log to get the data in view");
});
var remoteContactsPromise = this.getPromise(gRemoteContacts,"/origin"); //Wait for the other model to
$.when(localContactPromise, remoteContactsPromise).done(function(){
//When both models are loaded do this
console.log("I should be the second log!");
this.getView().setModel(gLocalContact, "localContact");
this.byId("label").setText("all loaded");
}.bind(this));
},
getPromise:function(oModel, pathToTestForData){
var deferred = $.Deferred();
if (oModel.getProperty(pathToTestForData))
deferred.resolve(); //Data already loaded
else
oModel.attachRequestCompleted(deferred.resolve); //Waiting for the event
return deferred.promise();
}
Full example on JSBin
A Promise is a object that has a done event. A Deferred is an object that has a Promise and a resolve() method that will raise the done event on that Promise. If you first call resolve() on the Deferred and then register a handler for the done the handler is immediately called. So you won't miss the event even if you were slower than the asynchronous load request.
But: If your model could not even been set on the component/core when your view initializes you have a severe problem as there is no such thing as a modelChanged event. I would recommend to create a empty model and assign it to the component in the components init-method and then use loadData() on that model.
Given I have resource id and data as plain JSON, how do I save that JSON to /cars/123/ ???
There seem to be no clear explanation. I don't have restangular element.
restangularizeElement might be the option, but it lacks any meaningful documentation.
All I know is that I want to save {make: 'honda', color: 'now blue, was red'} for car_id == 123.
Thanks.
If you have plain object you cannot use Restangular save function to update (it will make put request as object has id) object.
Easiest way to achieve it construct your end point url then call put function...
Restangular.one('cars', 123).customPUT(carObject).then(function(response){
TO-DO
})
If you want to restangularized your plain object you can use this one...
Restangular.restangularizeElement(null,carObject, 'cars').put().then(function (response) {
TO-DO
})
The comman way should be like this. Whenever you get object from backend with get or getList your object will be Restangularized unless you do not choose to turn them plain object by calling .plain() method of Restangular response. Then you can safely call .save() and it will automatically will be put or post accordingly...
Here is what worked for me. Thanks to #wickY26:
updateGroup: function (group, id_optional) {
if (!group.hasOwnProperty('restangularCollection')) {
// safe to assume it is NOT restangular element; sadly instanceof won't work here
// since there is no element class
// need to restangularize
group = Restangular.restangularizeElement(null, group, ENDPOINT);
group.id = id_optional;
}
return group.put();
},
Restangular offers a feature, extendModel, which lets you add functionality onto objects returned from the server. Is there any way to get these methods added to an empty / new model, that hasn't yet been saved to the server?
I wanted to do the same thing but didn't find an example. Here's how I ended up doing it:
models.factory('User', function(Restangular) {
var route = 'users';
var init = {a:1, b:2}; // custom User properties
Restangular.extendModel(route, function(model) {
// User functions
model.myfunc = function() {...}
return model;
});
var User = Restangular.all(route);
User.create = function(obj) {
// init provides default values which will be overridden by obj
return Restangular.restangularizeElement(null, _.merge({}, init, obj), route);
}
return User;
}
Some things to be aware of:
Use a function like _.merge() instead of angular.extend() because it clones the init variable rather than simply assigning its properties.
There is a known issue with Restangular 1.x that causes the Element's bound data to not be updated when you modify its properties (see #367 and related). The workaround is to call restangularizeElement() again before calling save(). However this call will always set fromServer to false which causes a POST to be sent so I wrote a wrapper function that checks if id is non-null and sets fromServer to true.