How to expose a widget directive API - angularjs

I'm creating a complex directive of a grid widget and I'm not sure where should I expose the grid directive API, i.e. it's properties (e.g. selectedItems) and methods (e.g. scrollRowIntoView(rowIndex)).
The options I'm considering are:
Expose the API on the scope (my directive defined an isolated
scope).
Expose the API in the directive's controller (if I
understand correctly this is what was done in the
ngFormDirective).
Expose a grid object on the scope which in
turn exposes the API.
Some kind of mix between the previous
options (e.g. properties exposed on the scope, methods in the
controller).
What I want to know is:
Is there a best practice for this use case?
What are the pros and cons for each alternative?
Are there any other valid alternatives?
Thanks!

Generally, you want to expose the bindings as attributes on your directive. That is, if I want to bind my array someItems to your grid, I'd expect your directive to look something like this: <my-grid my-items="someItems">.
You can expose hooks as attributes as well for things like "Run this function when the grid is resized". If I have a whenGridResized function on my scope, I'd want to set that as an attribute as well, like this: <my-grid onresize="whenGridResized()">.
In other cases you can't really use attributes, like your scrollRowIntoView() example. That would be a good candidate to expose in the directive controller, since that is something the directive user might want to call when other things occur in the system (such as DOM events).
So you should expose your API as attributes for events that happens inside your grid (things that you control), like onresize and ondelete or whatever. You can of course expose them in a controller as well.
When your directive needs to react to outside events like scrollRowIntoView(), you would to expose that in the directive controller since it would be a clunky API to expose such hooks as attributes.
You shouldn't expose your API through the scope since you want an isolated scope for your grid. Exposing it through the scope would mean that you have to set it your scopes parent, and it's almost never a good idea to access the parent scope directly.
TL;DR
A rule of thumb would be to expose as much as you can as attributes, and methods on your directive controller when attributes doesn't make sense. Exposing the same functionality in both attributes and your controller is a good idea since it's hard to anticipate how your users will use your directive.

Related

Calling C# Class method from AngularJs bound object

sorta new with Angular, odds are I can't do it... However,
What I'm trying to do is take a button and use the click event to call the bound objects codebehind method (without use of javascript functions):
i.e.: ng-click="MyClassObject.Method(param)"
Is this possible? and if so, what am I missing? :/
Note the object is bound, and data members are being used elsewhere in the view..

AngularJS data binding types

I know this is an old and 100 times-answered question, but things are getting more complex with the latest releases, thus causing me a lot of confusion.
I'd like to know what is the difference between the four currently available ways to declare a data binding for an attribute in a directive.
Specifically:
# Text binding
= Two-way binding
& Method binding (although some call it one-way binding)
< One-way binding
I'm interested in particular in the difference between the last two, given that they seem to have overlapping functionalities and I really can't tell the difference and the advantages of one against the other.
# Text binding:
This is used if we want to provide any static text to each instance of our directive. For e.g., any title or specific style/property component that needs to be passed to custom directive that is used to create a dialog.
= Two-way binding:
This is our normal angular two way data binding. For e.g., any live data update in a dialog or any user input (checkbox, radio etc.) can be achieved using this.
& Method binding:
As the name suggests this is primarily used for calling methods defined in the parent controller from the directive. It can also be used to evaluate a expression and bind the result to the directives scope. Typical usage might be responding to user events like when the user closes the dialog.
< One-way binding:
This I guess was introduced for higher performance situations, where we need not any updates from the directives scope to reflect on the parents scope. Typical usage scenario may be when we need to pass title, style, dialog configuration (modal/non modal, etc.) via a variable defined in the parent scope. Since such data are mostly not changed in the scope of the custom directive (our case dialog), one way binding would have a higher performance than a double binding. This is because angular watch cycle needs to monitor only the parents scope variables and not the directives one-way binded variables.
Note: I am not a expert in AngularJS and the answers above are best to my knowledge. They might be wrong in the view of a experienced Angular guy. Please pardon and correct me if there are any mistakes.
Official docs: https://docs.angularjs.org/api/ng/service/$compile#-scope-
Here is some information on the new one-way binding for isolate scope.
From GitHub:1
feat($compile):
add one-way binding to the isolate scope definition
This change allows the developer to bind an isolate scope / controller property
to an expression, using a < binding, in such a way that if the value of the
expression changes, the scope/controller property is updated but not the
converse.
The binding is implemented as a single simple watch, which can also provide
performance benefits over two way bindings.
Closes #13928
Closes #13854
Closes #12835
Closes #13900

Backbone listening to collection sync event in my View [duplicate]

What are the advantages and disadvantages of the following 2 lines of code? I don't understand why there are 2 different ways to do the same thing.
this.listenTo(app.Todos, 'change:completed', this.filterOne);
app.Todos.on('change:completed', this.filterOne);
Also when using .on, how do I determine is the default context?
listenTo is the newer and better option because these listeners will be automatically removed for you during stopListening which is called when a view gets removed (via remove()). Prior to listenTo there was a really insidious problem with phantom views hanging around forever (leaking memory and causing misbehavior) because view methods were referenced as event listeners on models even though the view instances themselves were long gone and no longer in the DOM.
If you want to read the back story for listenTo, search the backbone github repository for listenTo and read through some of the longer issue discussions.
As to the default context, several things can end up bound to this:
if you do the binding via this.listenTo, it will always be the view instance (pointed out by Wim Leers in the comments)
without this.listenTo, the story gets complicated
For misc events, it will be the global object (best to avoid this)
for DOM events, it will be the source element just like in regular DOM event binding
If you provide an explicit context (the 3rd argument to foo.on), backbone will use that (thus this is a more robust approach)
If you use the ECMA standard function () {//your event handler}.bind(this), you can also manually control the context (also recommended)
As #mu pointed out, _.bind or $.proxy are available alternatives to ECMA function.bind
For backbone views, doing this.bindAll('onClick', ...) will ensure the view instance is the this context when any view methods are used as event handlers
any events wired up by using the view's standard events property will get bound for you automatically to the view instance by backbone (this is belt & suspenders with bindAll)
So to summarize into some guidelines:
use the events property whenever possible as it is concise and correct
use this.listenTo for all bindings to models and collections
any additional bindings remember to bind the context reliably using your preferred method. I usually use ECMA Function.bind because hey, standards, but there are several good options here.
With listenTo, the object whose events you want to listen to is passed as the first argument. In the case of on, it is actually a method on that object.
The advantages of listenTo over on are:
The listener keeps track of all the event handlers, making it easier to remove them all at once when needed.
The callback’s context is always set to the listener itself.

When using Backbone + Stickit, do the view model objects need to extend Backbone.Model?

Loosely said, the various components in a MVVM pattern are
Model: this represents the data send by the server and sent back to the server. this contains no state related to display of the UI
ViewModel: this is constructed from one or models. this contains state meant for UI manipulation (is the button enabled or disabled). all logic meant for UI manipulation is stored here. this layer has no dependency on any UI framework (no jQuery calls)
View: this has tight coupling with the UI framework/underlying UI controls. One view observes one and only one view model. A view model can be observed by one or more views. The view is responsible for doing two-binding with the view model.
A presenter/coordinator: While not a part of the traditional implementation, in its absence the view model ends up with way too much responsibility. This guy helps coordinate making ajax calls (get/post), listening to events on the global event aggregator etc
Standalone Backbone has no concept of view models and data binding. In that scenario, the data returned by the server can be modelled as Backbone.Model objects. The bindings are done manually and a POJO can be used for view-model syncing.
If I wish to use Stickit for data binding, it appears that the view model needs to be an instance of Backbone.Model. Chiefly because the bindings work within the context of a Backbone.View and a Backbone.View expects a Backbone.Model object to be present as a property of the view. Also, a Backbone.Model raises change events and what not. I assume it will be difficult to observe a POJO. Again, this is my understanding from reading the Stickit docs. Please correct me if I am wrong.
A Backbone.Model has other methods on it that don't make sense from the point of view of a view model, like save, fetch etc. I was reading up on another mvvm library, Knockback. It can transform a Backbone.Model into a Knockout.js view model. Instead of passing in a full fledged Backbone.Model, it can also accept any POJO that has get/set methods and raises change events when the properties have changed.
Does Stickit have a similar contract wherein I can pass in a POJO that has get/set methods and raises change events? What is the recommended usage?
There's nothing in the source of Backbone.Stickit that requires that the model actually be an instance of Backbone.Model. So, it does appear that Stickit just needs some object that supports the contract provided by Backbone.Model--the various applications of set(), get() and on() are all I think you need.
Take a look at Stickit's test suite. If you wrote your own model API that passed that those tests (by replacing Backbone.Model with your own implementation in testScaffolding.js--and presuming the tests are thorough--then you should be able to use that model with Stickit.
EDIT: I may not have directly addressed the question. Stickit only requires that you use it in a Backbone.View, and that that view has either a model, or some other object specified by the optionalModel parameter you can pass to the stickit() function, that meets the contract provided by Backbone.Model.

Developing widgets in one view in Angular.js

I’d appreciate if you could share you view/experience.
Suppose you have a view which contains several widgets that share some of the data (fetched from a server). For example we might have a tree, list and breadcrumbs widgets in the same view, naturally a name of a single item can be displayed in more than one widget at the same time.
My question is what is the best practice of developing such views?
Specifically:
Are the widgets totally independent? (The easiest to implement, but suffer from performance problems)
If the widgets are dependent, do they communicate through:
A single model (introduces tight coupling between widgets and prevents further code evolution)
Events (lose coupling but error-prone due to lose contract, less explicit code)
Any other way
Provided those widgets have their own controllers and scopes, how do you propagate the change notifications from the URL (or any other event) to all of them?
For example if you wanna see an entity with a specific ID using URL routing, do you have a top-most view controller that is responsible to catch this change and notify all the widgets about it using some in-house mechanism, or do the widgets catch the event independently?
I guess all these questions are somehow related so feel free to answer them in whatever form/order you like.
Thanks.
Are the widgets totally independent?
I think that is too broad of a question for us to answer, as that really depends on what the widgets/directives are doing. Are you asking if they should be using isolate scopes? See also When writing a directive in AngularJS, how do I decide if I need no new scope, a new child scope, or a new isolated scope?
do they communicate through...
Again, too broad, sorry... it depends on what the directives do. Besides the ways you already listed, you could also communicate via
a service, which is probably what I'd use if I had more than two directives that needed to communicate
require: 'controllerNameHere'. With the require approach, you would define methods on your controllers using this instead of $scope. This method is limited to essentially one-way communication though: from the directive that has require to the directive that it is requiring. E.g., on the AngularJS home page, the pane directive requires the tabs directive. This allows the pane directive to call methods on the tabs directive's controller, but the tabs directive can not call methods on the pane directive's controller. (For more on this, see 'this' vs $scope in AngularJS controllers)
how do you propagate the change notifications
That depends on the type of scopes your directives have. If you are using scope: true for your directives, you don't have to propagate anything. They can all $watch some parent scope property (and because of the way JavaScript prototypal inheritance works, all of the directives can see the parent scope properties). If you are using scope: {...}, then you can use '=' or '#' to define local directive scope variables and use $watch to watch them.
If you are concerned about performance with $watches (since they are evaluated at least once every digest cycle), then events might be more appropriate.
Another thing to consider: do you want your directives to know about URLs or just scope properties? Using scope properties would likely make your directives more reusable.

Resources