I've recently started using Backbone.js. I like the architecture, in terms of features it's almost exactly what I need...
... However I found the following caveats:
For Collections get means something different than for Models. There is no set. Attributes should be accessed in a regular way. I find it rather inconsistent. It's easy to confuse models and collections sometimes. Is there anything that can be done to overcome this?
Assigning initial values inside Model.extend doesn't always work. For example assigning url will not override the default behaviour. This can only be achieved through a call to set() method. Again very error prone.
I still don't know whether it's required to use get/set inside initialize() call.
I don't understand why I can't just call _.bindAll(this) inside initialize() and I have to list specific function names to be bound like this: _.bindAll(this, firstFunc, secondFunc, ...). This is not very DRY.
I would like to know: what are the best practices regarding the mentioned situations? What do you do to make the framework more consistent - any monkey patching? Am I doing anything wrong / against the convention?
I'd be grateful for any good real world examples. I did find this: http://documentcloud.github.com/backbone/docs/todos.html and http://liquidmedia.ca/blog/2011/01/backbone-js-part-1/ and those don't address any of the mentioned problems. In fact they just present the simplest ideas and absolutely no border cases, so anything more complicated could be useful.
EDIT:
Ok, and there is one more fundamental think I don't understand:
Am I ever allowed to place additional attributes on extension like this: var SomeModel = Backbone.Model.extend({ myattribute: myvalue }) ?
If so, then why don't subsequent calls to new SomeModel().get("myattribute") work ?
What exactly is this inside initialize() ? Is it model class or model instance ?
EDIT(2):
Well, I found this: http://maccman.github.com/spine/. It looks like Backbone.js 2.0, shares a similar name too :). Haven't tested it yet, which might be a bit of a show stopper, as the library is very recent. However from the docs side of things it looks very promissing. It gets rid of most of the problems that I found, it simplifies the API, it even gets rid of the dependency on underscore.js which for a library is a good thing. I'll post my further findings here.
Ok, I think I can say it quite confidently now: Backbone is dead, long live Spine.
Spine isn't exactly a fork of Backbone. It is however very similar and clearly inspired by some of the design decisions. It could be said that the author tried to retain as much as it was possible the original backbone API, getting rid of everything unnecessary or illogical. I find it also easier to extend. The list of changes includes among other things:
Getting rid of the dreaded Collections. "class methods" are used instead,
Getting most out of js prototypical nature (i.e. no get/set is needed). Attributes are accessed directly. An explicit call to save() is required in order to trigger an event.
Views and Controllers are now merged into new type of Controllers together whose purpose is to respond to DOM events and bind to model events.
The name :)
I find those design decisions coherent and sensible.
The reason there is no 'set' for Collections is because Collections are not arrays, they are sets, which are potentially ordered. The only supported way to place an element at a particular position is to add it to the collection and then sort the collection.
Related
I'm trying to access the properties of an object in an app called Papers3 using JXA. I'm new to JXA and this is proving challenging, especially because of the lack of documentation.
Here is a shot of the dictionary for the object I'm trying to look at
I'm trying to get the IDs for the currently displayed windows in the app.
My attempt at this is:
var Papers = Application('Papers');
Papers.includeStandardAdditions = true
Papers.libraryWindow.displayedPublications()
Running it throws an error and the output is:
Error on line 4: TypeError: Papers.libraryWindow.displayedPublications is not a function. (In 'Papers.libraryWindow.displayedPublications()', 'Papers.libraryWindow.displayedPublications' is undefined)
Error -2700: Script error.
Also, if I call just Papers.libraryWindow
The result is:
[function anonymous] {
"name":"",
"prototype":{"constructor":[function anonymous]}
}
I'm not sure what to do.
Well, JXA is broken obfuscated moribund junk and AS not much better off either, but the key thing to understand here is that Apple event IPC is not OOP, it is RPC + simple first-class relational queries. Despite the syntactic sugar, its closest relative is actually SQL database programming, not browser DOM manipulation, so once you get your head around that it’ll [hopefully] start to make a bit more sense.
An “AppleScriptable” application presents its data as a heavily abstracted relational graph—an “Apple Event Object Model”—where each node is related to other nodes by one-to-one and/or one-to-many relationships. There’s no such thing as “classes” or “objects” in the OO sense; it’s just the jargon that got attached for documentation purposes. Thus what an application’s dictionary calls a “property” is either a simple attribute containing a primitive value (number, string, list, etc; e.g. the name property of a Finder file) or a one-to-one relationship (e.g. the current track property of iTunes’ application), and what it calls “elements” is a one-to-many relationship (in your case, the libraryWindows elements of Papers’ application object).
For example, Papers.libraryWindows.displayedPublications.get() should return a list of the displayed publications of every library window in Papers (though whether that actually works in practice depends on how well implemented an app’s AEOM is, not to mention JXA’s own implementation issues); or you can use various reference forms (by-index, by-name, etc; though several are broken/unsupported in JXA) to narrow your query to, say, just the first library window, e.g. Papers.libraryWindows[0].displayedPublications.get().
You might get some insight from browsing the NodeAutomation documentation, which includes a rough overview of AEOM and how to assemble queries which you then send to it via commands (remote procedure calls) to resolve and process as it sees fit. JXA syntax isn’t as pretty, and various operations that work perfectly in AS barf in JXA, but it’ll give you a rough idea.
That said, I strongly recommend sticking to AppleScript. The language is a mess, but at least it has some documentation and user community to help you find your way around it (even if they don’t deeply understand it either).
It's a little detail, I think. libraryWindow needs to be plural and it's necessary to specify which one. You can use several forms:
Index form eg. libraryWindows[0]
ByName eg. libraryWindows.byName('Papers')
So, to access the first library window, you use: libraryWindows[0].
Try this:
(() => {
'use strict'
const app = Application('Papers');
const oWin = app.libraryWindows[0]
return oWin.displayedPublications()
})();
For Papers 3 specific JXA examples, see:
mac-scripting - Automation scripts for macOS
For more general info, see:
JXA Resources
In Ember.js, we use Ember's own object variants which recommend/necessitate using this.get and this.set in order to access object attributes.
I (mostly) understand why this is done, and appreciate the consistency and flexibility it adds to the Ember programming experience, but I do feel that I lose out on my IDE's sanity checking.
With Jetbrain products (or any good IDE w/ deep analysis and completion) I can usually rely on symbol suggestions to make sure I'm choosing the correct variable name. Entering in strings with ember relies on me to get the name right, and I'm a fallible human.
I have a few thoughts regarding possible solutions.
Some IDE plugin which does static analysis to suggest the correct string to use
An ES6 or alternative transpired language which accesses members the ember way by default
Some way of automatically establishing string constants where I need them
Some ember debugging setting which at least throws warnings if I try to get a variable which hasn't been defined.
I would also find it useful to throw warnings if ember catches me trying to set an attribute to undefined.
Hopefully, someone will tell me that one of these solutions exists, something better has been thought of, or my problem isn't really a problem.
(An example to illustrate my problem:)
In the following snippet
const email = this.get('email');
const newInvitation = this.store.createRecord('invitation', {email: email});
I am trying to get the attribute email but the real attribute I meant to get was called emailAddress. When I create the record, I do so with an undefined email field which isn't caught until later in the code.
It wasn't terrible to debug, but if I have to manually sift through every line of code every time I misspell something, I'm going to waste a lot of time and be a sad debugging-boy. Help!
Currently we don't have a good solution for this. However the future looks bright!
Currently there is a lot of work going on in the ember-typings repository to build a typescript definition that will allow the typescript language server to give you that completion. This will give you completions for things like this.get('foo') but not for things like this.get('foo.bar') in near future.
Also I've build this, which will allow you to omit .get and .set on browsers that support the proxy object. However this is more a proof-of-concept then something you should use in production!
If you just want debug messages if you access a property thats null you can use unknownProperty:
unknownProperty(key) {
console.log('access to unknown property');
}
However I sometimes its required to access an unknown property for code like this:
if(!obj.get('foo')) {
obj.set('foo', 'bar');
}
So overall I would recommend you to try out typescript, because thats probably the solution that will give you a good developer experience soon and good support from the community as well. Interesting is also the ES classes RFC, that shows, that ember goes toward standard ES classes and at some point we won't .set and .get at all.
Also glimmer integration is going forward, and inside a glimmer component you won't need .set and .get.
Also I don't recommend you ember script. I tried it out, but there is basically no-one using it, and no support at all.
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 am wondering how to structure a KnockoutJS application the right way.
The official documentation almost always uses just one single ViewModel!
After only a few implemented functions my code became very confusing and coming from an object-oriented background I am very allergic to architecture like that. So there must be a better solution.
Being not very experienced with JavaScript I was searching Stackoverflow and found those three options. So I tried the first two options and I am not happy with them:
Having multiple ViewModels like here.
I find it very difficult to decide what DOM-element gets what ViewModel. Also there were several functions called from outside the DOM-element. Maybe I used too little ViewModels with this kind of architecture but communicating between ViewModels seemed to be different and somehow shouldn't be necessary I hope. So how to do that properly?
Having sub views and utilizing the with binding (the second option from those three).
This was my preferred type of architecture because you can have document-wide bindings out of one view model but you can also structure your code into sub-chunks and bind them to wherever you want by using the with binding. This option though requires object literals instead of functions, which are inferior as described in this answer.
I haven't tried method three because it seems a little overkill and also uses object literals.
So is there a method to structure my code and also have full control without using object literals?
I hope this was not too confusing :-P
For any of the options that you mentioned, you do not need to use object literals. The samples just used them to simplify the code. You can choose to create the individual view models in any way that you see fit.
For example in #3, you can use a constructor function like: http://jsfiddle.net/rniemeyer/PctJz/149/. Of course, the actual data would get passed into the function rather than being static. Same with #2, you just would have it wrapped in the "View" object.
what is the advantage/ reason for backbone-js to use the syntax
//using a Model instance called model
model.get('attribute')
and not
model.attribute
Im just starting to use backbone and I always ind myself trying to access the attributes directly
If you look at the source code, the get function just calls to this.attributes[name].
http://backbonejs.org/docs/backbone.html#section-31
The benefit, though, is at least two-fold:
1) a consistent API that reduces the amount of code you are writing
2) the ability to override the get method and provide more complex access control
For example, there are several plugins for backbone that override how models work in order to provide nested model capabilities. it's very easy for them to allow you to write a get method like this:
model.get("submodel.attr")
and have that parse out the attr of the submodel sub-model. Without the get method, it would be more difficult to make this consistent with the API.
The underlying benefit from this is encapsulation, though. Until JavaScript provides true get/set properties that let us write code for getters and setters, we'll be stuck with work-around methods like Backbone's get and set.
Well .. for starters, model.attribute is absolutely NOT correct. model.set() is required in order to get change events to fire. You're very likely to forget this if you get in the habit of using model.attributes[attribute] instead of model.get(attribute)