There appear to be a number of different ways how to access properties of a Sencha (Touch) model. However, I don't seem to be able to find proper documentation of which is the "correct" way of doing it.
Model creation
var model = Ext.create('MyApp.model.MyModel', {
name: value,
foo: bar,
...
})
Property access
model.get('name') or model.set('name', newValue)
model.data.name or model.data.name = newValue
model.raw.name seems to always return a string no matter what the data type in the model definition is?
Let's sort this all out:
get and set methods are the intended accessors for model field values.
model.data is the object that stores the client side model value, that is that have been converted from the data received from the server proxy using the fields configuration (type, convert method, etc.).
model.raw is the raw data that was received from the server proxy, before it was converted to client side application domain model values. You should avoid using it, or you will tie yourself to your proxy/server.
model['name']: as you've said, it doesn't work. Don't hope for it to come back (I don't even really understand that it worked at one point).
Now, which one should you use? Clearly, the last two ones are already out of the match.
The model.data object should give you the expected result in most cases (see bellow), and should give you a marginal performance gain other calling a function.
However, IMO you should always prefer to use the getters and setters, for two reasons.
First, it might happen that someone in your team (or you from the past) decides that the getter/setter is a good point to add some custom logic. In this case, bypassing the accessor by using the data object directly will also bypass this logic, and yield unpredictable result.
Secondly, getters and setters make it really easier to debug some situations, by making it easy to know from where modifications of the model values are coming. I mean, if one day you were to ask yourself "f**k, why is my model field value changing to this??". If all the code uses the getters, you'll just have to put a breakpoint in there, and you'll catch the culprit hand in bag. On the other hand, if the incriminated code uses the data object directly, you'll be stuck to do a whole project search for... You can't tell exactly what... data.name =? data['name'] =? name:? etc.
Now that I think about it, there is yet another reason. A deprecated one apparently. But the data object name used to be customizable using this persistenceProperty option. So, in some cases, the data object won't even be available, and code doing model.data.name instead of model[model.persistenceProperty].name would crash, plain and simple.
Short answer: use the accessors.
Related
Learning Ember.js and have a reasonable understanding of getters and setters (accessors) through Ruby and Java.
In Ember/Javascript, I seem to have a very serious lack of understanding. For instance in my controllers/models, I don't have a clue whether to use object.set(property,value) or refer them directly object.property = 'value'
As an example, in my earlier question (How to get Model values in Controller), part of working answer was to use object.name instead of object.get('name'). It worked but I miss the basic understanding.
Would appreciate some clarifications.
The rule is: You should always use .get()/.set() when you are in your .js-files. When you are in your templates (.hbs or other) you should not (you can't do it).
If you access a property via myObj.myProp it will work for regular properties, but computed ones won't. If you set a property via myObj.myProp you can still get the value back, but bindings and observers won't be notified that it has changed and won't updated properly.
This is a design decision by the Ember team which allows for efficient bindings/observers instead of doing dirty-checking of all bound/observed properties (which is what Angular currently does).
I made a small jsbin showing this. Three values are bound initially, the button then changes one and logs it into the console (so make sure to have the console open), the binding isn't updated but the value can be retrieved. It then tries to get a computed property via myObj.myProp which returns undefined and then the regular way.
http://emberjs.jsbin.com/cipapaxevi/2/
Also, as a side note. If you want a property thats on a child object to what you have you can access it via myObj.get('myProp.myOtherProp') instead of doing myObj.get('myProp').get('myOtherProp'). It saves you from the worry that myProp could return null or undefined.
That's the way Javascript works and it's one of its disadvantages. It doesn't have public/private proprieties nor methods. Therefore, we should rely on good comments in the code.
I am not an expert in Ember, but when I face the similar problems in JS I usually look at the source code of the library to see how it's constructed and then make a decision. That's why probably js libraries are usually shipped with both min and dev versions.
However, if the object has special methods to access its properties then they are there for a reason, so use them instead of the direct access to the properties. As I said above, in Js you can't make properties be private or protected.
I am working on a JavaScript application with a server-side component. The aim is to have multiple different objects on a canvas that are synchronized (i.e., have the same appearance) between multiple browsers. The synchronization is done by the server-side component which broadcasts the individual changes to all browsers. Whenever an object changes, it has to notify the server about which will then take care of notifying the other browsers.
The objects on the canvas are represented by JavaScript objects whose attributes determine the appearance for the user. Of course, not all of the attributes are important for the appearance. Hence, only changes of important attributes have to be transmitted to the other browsers. There are different 'classes' of objects, but all objects 'inherit' from a common 'superclass' (I know, the class inheritance terminology doesn't really work in JavaScript, but in this case, I think it is easier that way).
Now, I have some trouble to send the client-server notifications in an elegant way. Currently, I have setter-methods for all the important attributes of the different objects. These setter-methods call a function which sends the notifications to the server.
I don't really like that solution, since it introduces much boilerplate code. Ideally, when I create a new object, I would like to be able to just specify the important attributes an be done with it. The logic that takes care of monitoring the changes of these attributes could be inside the 'superclass'. But I have no idea how to implement this. Maybe there is a way to build the setters dynamically at runtime? Or maybe there is some other way I did not think about?
If anyone can think of a solution to this problem, I would be glad to hear about it.
Thanks in advance!
Edit:
I had to revoke the accepted answer (creating getters and setters dynamically via Object.defineProperty) since though I thought it would solve my problem, it doesn't really. I now get notified when a property is changed via direct attribute assignment which fires the setter, e.g.:
SynchronizedObject.importantProp = 'someValue';
But as I noticed, in many cases the importantProp is some more complex object. And those objects are usually updated via the getter, not the setter.
SynchronizedObject.importantProp.x = 'someValue';
As far as I can see, I have no chance to notice changes done in this way with my dynamic getters/setters implementation. To use it, I have to change the way I am accessing my objects. Something that works:
prop = SynchronizedObject.importantProp;
prop.x = 'someValue';
SynchronizedObject.importantProp = prop;
That way, the setter is used and everything works out fine. But this feels really awkward and I don't want to have to think about the synchronization every time, I set a property. So it seems to me, the solution is not really usable.
Can anyone help?
How about one set function?
MyObj.prototype.set = function(key, value) {
this[key] = value;
// do other things
};
You could combine this with an EventEmitter implementation to make it easy to observe changes.
This is exactly what __defineSetter()__ is intended to support. Check out John Ressig's JavaScript Getters and Setters blog post for some good examples. It would be pretty simple to fire off an event from inside a setter.
You may want to consider the MeteorJS framework if wheel reinvention is not really your bag.
I'm using breeze.js in a SPA and have problem with entities loaded from server. Namely, entity created from metadata (using metadataEntityType.createEntity()) and added to entity manager has all of the properties like server-side model, ready for binding with knockout, and that is cool.
The problem is when I use entityModel.EntityQuery.from("WorkOrders"), the successCallback that I pass to its .then promise gets a data object with results property which contains an array of vanilla js objects where all of the properties with value == null are missing (this is exactly how server sends that data through the wire, but I suppose that it is how is meant to be because breeze has all metadata on the client and does not need all properties to know that they exist).
I have my custom constructor which can make full-fledged knockout object like the one from createEntity(), but I'm thinking that there must be a better way to let breeze handle this for me automatically. I'm not sure if I should add these objects to entity manager as I suppose they should be already there, and I registered my custom constructor to store using entityManager.metadataStore.registerEntityTypeCtor, but that does not change what success callback gets, it is always plain JSON just like it was sent from server.
Update: Code of method which is called on the server to return json payload is
[HttpGet]
public IQueryable<WorkOrder> WorkOrders()
{
return (IQueryable<WorkOrder>)_contextProvider.Context.WorkOrders;
}
As #Jay pointed in its answer & comment, that may be the cause of behavior. This is the JSON payload returned:
[{"$id":"1","$type":"WorkOrders.Domain.Models.WorkOrder, WorkOrders.Domain","Approved":false,"DateModified":"2013-01-02T22:31:20.897","RequestForEstimate":false,"Id":5}]
This issue was caused by a model being in a different namespace than the DbContext/ObjectContext that hosted it. Previously this was documented as a known limitation.
As of v 0.83.2, breeze now allows model namespaces to be different from the DbContext/ObjectContext namespace.
Please confirm if this fixes the issue.
Thanks
I'm not quite sure I understand what you are asking. Is it that you would like properties with a null value on the server returned to the breeze client with a value of null instead of being undefined, or am I missing the issue?
If this is the issue, I agree that what you want would be useful and I will add it as a feature request.
Another possibility that you might want to look at is to use the 3rd parameter to the 'registerEntityTypeCtor' method that lets you pass in an initialization function. This function will be called once for each entity being constructed, 'after' it has already been materialized. This means that you can iterate over the properties or the object and set any that have a value of 'undefined' to 'null'
Does this make sense?
First of all, I must say that I'm very new to Google Closure, but I'm learning :)
Okay, so I'm making a web app that's going to be pretty big, and I thought it would be good to manage all the AJAX requests in one XhrManager. No problem there.
But, is it possible to have some kind of default callback that would check for errors first, display them if necessary and then when it passes, launch the "real" callback? I'm talking about a feature like the decoders in amplify.js. Here's their explanation:
Decoders allow you to parse an ajax response before calling the success or error callback. This allows you to return data marked with a status and react accordingly. This also allows you to manipulate the data any way you want before passing the data along to the callback.
I know it sounds complicated (and it is, really), so the fact that I'm not that good at explaining helps a good deal too, but yeah.
The solution I have in my head right now is creating an object that stores all the 'real callbacks', of which the 'error-checking callback' would execute the correct one after it finished checking, but I feel that's a bit hack-ish and I think there has to be a better way for this.
Since you always have to decode/verify your AJAX data (you never trust data returned from a server now do you?), you're always going to have different decoders/verifiers for different types of AJAX payloads. Thus you probably should be passing the decoder/verifier routine as the AJAX callback itself -- for verifications common to all data types, call a common function inside the callback.
An added benefit of this will be the ability to "translate" unmangled JSON objects into "mangled" JSON objects so that you don't have to do use quoted property access in your code.
For example, assume that your AJAX payload consists of the following JSON object:
{ "hello":"world" }
If you want to refer to the hello property in your code and still pass the Compiler's Advanced Mode, you'll need to do obj["hello"]. However, if you pass in your decoder as the callback, and the first line you do:
var decoded = { hello:response["hello"] };
then do your error checking etc. before returning decoded as the AJAX response. In your code, you can simply do obj.hello and everything will be nicely optimized and mangled by Advanced Mode.
I'm using JSON.stringify and JSON.parse to store and retrieve objects from localStorage. However, it appears that JSON.stringify strips out the instance functions from the object. Thus, after JSON.parse, I can no longer call myObject.doSomething(). I know that I can attach this function manually: myObject.doSomething = MyClass.prototype.myFunction, but that'll be troublesome if this action is repeated many times in the web app. How do people normally do this in JavaScript?
JSON obviously does not hold onto the functions themselves is only stores simple typed variables. The way I have addressed this in the pass is to be a restore method in my class and simply call that method with the data from JSON so as to re-populate the class with the data that belongs in it.
I have done this extensively with the Value Object ( VO ) design pattern in my code base and it has worked quite well for me. Just a word of a caution though, Ie7/Ie8 are not terribly friendly with this approach if you try to communicate across windows. As I recall I think it is IE7 that does not return the right "typeof" for some properties so I ran into a whole bunch of challenges in my restore when cross-window communication was involved.