I'm rather impressed with AngularJS, but one of a few things that is bothering me is that it isn't as easy as some other frameworks to discover the linkages between code and templates. For example, a template for a directive can contain many other directives, and those directives can be tags, attributes, even id or class names, so they are not immediately visible when looking at the template file. The only way I know to discover all the directives in a large template file is to painstakingly look at every line of markup. I suppose I could write a program to discover all the directives I define and then search all my templates for uses of those directives, but is there another way?
Related
I have a large app with a structure and UI that has been designed to meet the original requirements.
I am now faced with a situation where I have to make an alternative read-only "view" of certain parts of the app for embedding in an iframe (I have no say in this, this is how it has to be).
I'll be referring to these two ways of viewing the app at the "display context".
I am struggling with visualising how to achive this, I can see two solutions both of which have distinct disadvantages:
Have lots of ng-if directives attached to template elements, the ng-if would be bound to the current display context of the app and show/hide elements depending on how it was being used. Even if these were one-time bindings, it would potentially turn the templates into an unreadable mess of nested ng-ifs everywhere
Create entirely separate templates for the two different display contexts. While much cleaner than the first option, it would mean a lot of duplication and maintaining two templates per view whereas previously it would be one.
I should add that the nature of the views is very ng-repeat heavy, a list of data containing categories, each category contains items, each item contains a multitude of data, at each level data may need to be hidden/displayed/manipulated for display depending on the display context. I have made heavy use of directives and components to break things up into logical chunks, however these directives and components are still very much geared towards the original use, rather than the newly required one.
I have also considered creating an entirely new app for this, however I'm not sure this would bring any benefits as I'd be using controllers and injecting services containing tons of stuff that would be never used, I'd also be increasing my duplication problem.
Does anyone have any feeling, suggestions on a good way forward for this as at the moment I'm feeling anything is going to be horrible.
Many thanks
Long story short, let's say one app has multiple pages with:
a form
a list
pagination
each page may require (now or in the future) custom actions to be implemented
My question is, witch is the preferred Backbone way of handling this and why (please argument) ?
Define, a pagination view, a pagination collection, a search model, search view, etc, and initialize each one as a child view in all the necessary pages. This means we will have to append child view elements into the 'master' element, and handle all the communication between these in all necessary pages.
Define a pagination view (with it's own pagination collection and search model) and extending it across all the necessary pages. This does mean that we will have to make use of template partials (for forms, pagination, etc) and bypasses the need of handling communication between child views while also removes the need of appending/removing child view elements.
Please add your way of handling these cases if not found above, remember to argument.
My personal opinion would be 2. And that is because it removes a lot of hustle with communication between child views and it makes everything much more easier to read just by extending classes, instead of having to 'manually' init child views. It also gives one the option to rewrite behavior per page when needed.
I think #2 is a poor choice.
It's a very good idea to keep templates as simple as possible. They are basically just the markup that's generated for some input object. In order to get that object to the template, in MV* frameworks you have Views, that can either pass a model to the template or send some formatted data to the template (I prefer this where possible).
Partials just create markup. You'll still have to handle events, updates to the DOM and rendering inside the view. If you only use one view it will have to handle a lot of things, something associated with poor maintainability and a more bug prone codebase.
You'll either have a lot of code in the views, or you'll end up with a lot of mixins or doing a lot of inheritance - and I have no idea which is worse.
Big things are a lot harder to test and to reason about. Avoid doing big things.
I think that another big problem with the template partials approach is the fact that you cannot rely on type information (something like interfaces), on the object that ends up in the template. It's probably easy to make it work when you have a partial or two that you just created, but, in time this information will get lost, leading to a bad development experience.
You'll need to make sure views unrelated to your changes are kept updated with the partial changes you just made for a feature.
Keep in mind that software is never done. Things always change.
Instead of thinking about relationships between models you'll have another complex challenge that you need to handle: the coupling of views through partials.
The alternative is a lot better. Composing specialized views is a good approach because each has it's own internal, smaller state and just it notifies listeners when some action takes place. Nobody cares about what's going on there until something happens and then you just get concrete data.
Going with #1 helps you deal with complexity in your application while allowing you to reuse them in other contexts.
I started with a directive that restricted to be used as an attribute, and when used, it would add ng-mouseover to the element it was applied. It seems to be a trivial task, you just need to $compile it, right? Wrong, it will work only until you decide to have an isolated scope. here's jsbin that explains what I'm talking about
I couldn't solve that problem, anyway.
Now, maybe it's possible to solve this dilemma by making the directive restrict:'E' and transclude whatever is inside of it. Works? Sure. jsbin
But now, I realized that I need to apply those mouse events not to the element itself but to its parent. As in the first case where I struggled to add attributes and keep the content without having scopepocalypse, once again I'm having similar headaches.
Can you guys show me one simple example how to make a directive with isolated scope that adds ng-mouseevent attributes to its parent?
Sometimes I feel stupid for deliberately overcomplicating my own life. Maybe I just need to attach good old event handlers to the parent element right from inside of directive's controller? Yes, seems like an easy fix, but that would be conceptually wrong, and againsts angular's traditions, isn't that right?
The angular way would be to never dynamically attach directives to parents if you're implementing the compile or link functions. The compile and link process is a one way street - meaning parents are compiled before children. Sure you can try to go against traffic, but doing so is difficult, risky, and more trouble than it's worth. By adding directives to a parent, and then trying to recompile it, you'll probably end up recompiling directives multiple times, or worse, introducing a subtle memory leak. It's a difficult road, I'd advise against it. It is not the angular way.
Instead of asking yourself, how do I add directives to my parents, ask yourself, how do I add directives to my children? Child directives can communicate to parent directives through the 'require' property. Usually, this is flexible enough to handle most situations.
To answer your second question, it is perfectly acceptable to hook into JavaScript events within a directive definition (how do you think ng-mouseover was implemented?). If you do, you should do so inside your link function.
I'm writing a javascript web app using Backbone and Marionette, and my templates are created using Handlebars.
I have a view with three sections: a progress indicator, results list, and footer. Each of these may be shown or hidden based on if an operation is in progress or if there was an error.
Should I include conditional code in the Handlebars template, along the lines of {{unless resultsFetched}} and do this.render() often, or use javascript in the view like this.ui.resultsList.show() and this.ui.resultsList.hide()?
Thanks.
Update
Here are what I think are some pros and cons to having logic in the view templates:
Pros:
I think this looks like a declarative (instead of imperative) style, where the view says that it'll act a certain way based on model state.
As things get more complex, it'd probably be easier to read a template that has conditional logic than javascript code where show() and hide() is used extensively.
Cons:
Is the MVC architecture still being obeyed?
This goes against Mustache's philosophy of logic-less views
As a general rule, you'll want to keep as much logic in the Views as possible and only have presentation in your templates. That isn't always practical to be sure, but the larger your app gets, the cleaner you're going to want your templates to be.
That being said, today I used a for loop in an Underscore template because I had no need for a CollectionView-ItemView combo for the little things in the list that I was adding to the DOM.
TL:DR; Try to stick to my first paragraph, but use your instincts :)
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.