Some comments inline

Субота, 28 грудня 2013 р. 04:41:38 UTC+1 користувач Daniel Tabuenca написав:
>
> This is a common question/concern by those seeing angular for the first 
> time. In a sense, it seems as though we've gone backwards in time when we 
> used to do things like:
>
> <div onclick="doSomething()">
>
> About the time that jquery started becoming popular, a lot of the 
> web-development community got sold on "unobtrusive javascript" which a 
> large part of it meant you would clean the dom from all javascript and then 
> attach javascript handlers entirely from within a script. One of the 
> greatest benefits of this approach as it evolved is that it freed us to a 
> large extent form having to define our handlers globally.
>
That's only small part of the top of the iceberg. For me other problems of 
these approach are much more important, global functions is just one 
maifestation. It all comes down to one and the same problem (as always) - 
no separation of concerns. You clearly have at least two tasks when 
presenting UI to user: visualize (output) and behave (input). Behavior can 
even be a subject to aspect oriented programming as it can become a cross 
cutting concern (e.g. resizing and drag and drop). It's always a good idea 
to separate those concerns. BTW I'm not per sei following unobtrusive as 
I'm long time forgot it's concepts even.

> We could now create our handlers in modularized non-global code and then 
> attach them directly to the dom, and this is the main concept with a lot of 
> the jquery-based frameworks such as backbone.js. 
>
> However, this style of programming did not come without it's downsides. 
> While the intent was to keep javascript unobtrusive, in practice both the 
> javascript and the dom intruded on each other all over the place.
>
> The dom became filled with extra markup and classes unrelated to style to 
> make it selectable as well as to hold state:
>
> <div> 
>   <span class="show-person-details" data-person-id="42">Person 2<span>
>   <div class="person-details hidden" data-person-id="42">This is the 
> details</div>
> </div><div>
>  <span class="show-person-details" data-person-id="43">Person 1<span>
>  <div class="person-details hidden" data-person-id="43">This is the 
> details</div>
> </div>
>
> Well two things here:
   * even in this incarnation it's still "ok" to declare in the view the 
support of some behavioral interface, it's not how I prefer to do it but 
it's better then inlining the implementation on that place
   * in proper setup you can easily get away from view even bothering about 
knowing that id - your view is bound to a model which holds the id and your 
behavior can read that from model, the only requirement from the view is to 
mark the action blocks, but again even that could be replaced with mini 
behaviors and scopes.

> The javascript became littered with complex selector expressions, css 
> classes
>
again I think quite good abstract interfacing (you can easily scale to XML 
like that for example). 

> , and lots of dom manipulation code:
>
>   $('.show-person-details').click(function(ev){
>     var personSpan = $(ev.target);
>     var personId =  personSpan.data("person-id");
>     $('.person-details[data-person-id='+personId+']).removeClass("hidden");
> });
>
>  That's not per sei necessary if you have good view technology which takes 
model as input and renders it - you code changes quite drastically to a 
more readable and scalable version. And this example is not much better 
than previous - you still define one global listener where everything is 
bulked together, it's maybe unobtrusive but not properly separated.

> This is just a simple example, on many a real-world project this can get 
> much worse. In any case the dom clearly intruded into the javascript, and 
> the javascript intruded into the dom (in the form of unecessary selectors 
> and data attributes, hidden inputs, etc...). 
>
> The philosophy of angular is to elminate the real fundamental issue we had 
> with onclick= style handlers which is the fact that they were global. It 
> does this by creating a scope hierarchy (controlled by Controllers and 
> Directives) that allows you to map state neatly and in a modular fashion 
> onto the DOM tree we are all familiar with. 
>
As I'm mentioning - it's not what I would like to achieve - I would like to 
keep behavior and rendering separated and I would like to be able to use OO 
means to model and encapsulate behavior (even for cross cutting behavior). 
Behavior can span multiple events and can have own presenataion models, it 
is a mess to take all behavior event handling (and possible state) bulk it 
all together and then mash it into the view. It hurts all aspects that I'm 
striving for.

> I can do the equivalent of the above example purely in the html (assuming 
> that persons object already exists in our scope):
>
> <div ng-repeat="person in persons">
>  <span ng-click="person.detailsVisible= true">{{person.name}}<span>
>  <div   ng-show="person.detailsVisible">{{person.details}}</div></div>
>
> This is very easy to understand, even for someone who's never used 
> angular. Simply by looking at the markup I can tell exactly what the 
> behavior of this will be. Furthermore, I've removed the need to do any 
> custom javascript logic or dom manipulation in order to show/hide the 
> details. 
>
Now few things about this:
    * say someone puts 0 or -1 or {} or [] or whatever other value there - 
which test of yours fail?
    * what stops me from starting to write 'person.detailsVisible = 
person.details ? !person.detailsVisible : false;' (and again go untested)?
    * so say nothing stoped me from doing above how do I support touch? I 
would guess in Angular you would push it in scope and mix data with 
behavior, well ok...
    * what if I have not only person but also group or some other entity 
and and it happens to also have details but the display is quite different 
- what is the appropriate structuring in angular to achieve this quite 
simple structure?

It just feels like a natural structuring for me to have separation between 
Presentation, View and Behavior.

While it might not be incredibly difficult in the simple jQuery example 
> above to tell what the code might do, I've often have had to jump on 
> existing large projects where figuring out what the page is supposed to do 
> is an incredibly difficult task. The DOM is litered with classes, but which 
> ones are for style? Which ones are to make it easier to use selectors to 
> bind some event? How do I know what's clickable, and how different parts of 
> the page might be related? How am I supposed to know that deep down in some 
> obscure part of the code some event is bound that does something I did not 
> expect?
>
 
That's essential problem with lack of separation of concerns: 
   * when resolving problem from rendering space (how to visualize 
something or why it's not visualized as expected) you look into view 
(templates, HTML, CSS, media)
   * when resolving problem from behavioral space (how to react on input, 
why reaction on input is incorrect) you look into behavior (JS behavior 
modules) and it's interface part in view (templates)
   * when resolving problem from presentational space (what information to 
present to user, how user can reach needed goals) you look into your 
presentation model (JS modules)

And of course it should be a clear syntax where the binding points are. I 
prefix classes in HTML with js- to indicate that they are behavioral 
markers, plus CSS is linted against using classes with those prefixes. As I 
don't really care about validators (we use XHTML anyway) I could use just 
custom attributes to simplify things.

> Sure, with discipline, great care, and tight organization you can 
> alleviate some of the pain, but I've been on projects with very talented 
> developers and strict code organization that still eventually become 
> somewhat of a mess.
>
> One of the difficulties I think you will face is in trying to integrate 
> with your existing way of doing things.
>
> While angular itself is fairly low-level, flexible, and certainly not as 
> perscriptive as some other frameworks (e.g. ember.js), you will still run 
> into quite a bit of friction if you don't do things "the angular way". 
>
> What people often mean when they say "the angular way" is really just 
> designing the application in a more declarative way. This is fundamentally 
> different than the imperative patterns people are used to from using jQuery.
>
What I describe is purely declarative separation, even behavior classes can 
be structured by convention to have declarative look and be inspectable. 

>  In the first person/details example above the code is entirely 
> imperative. The click calls a click handler which instructs the browser to 
> lookup a piece of dom and hide it. The click is tightly coupled to what 
> must happen as the result of the click. 
>
> In the angular (declarative example) we break things up into independent 
> actions. The click simply sets the state detailsVisible on the person. 
> The details simply is setup to show the details whenever the detailsVisible 
> flag is true. It is completely decoupled from the click action. It doesn't 
> care whether the detailsVisible flag was set by a click handler, by 
> javascript code, by some bound checkbox, loaded from the server that way, 
> etc.... 
>
What I describe is the quite same, just the way how actually that 
"detailsVisible" is changed is moved into presentation model into something 
like toggleDetails() but than how is that action triggered is encapsulated 
in behavior entity. So your concept of declarative view stays there it is 
automatically updated cause the scope changed, but the only thing it would 
describe on how is that happen from that view is by mentioning behavior 
class name.

A hypothetic syntax in Angular:

<ng:repeat items="persons" var="person" behavior="ExpandableBlock">
   <span class="js-expandable-block-toggle">{{person.name}}<span>   <div 
ng-show="person.detailsVisible">{{person.details}}</div></ng:repeat>

In any case, what I understand from Majid is I should use directive for 
that. That's kinda clear, but that's what I also miss explicit concept for 
behavior and rather very low level processing instructions. So I already 
tried to evaluate how I can bind my behavior classes to some custom 
directive, but for now what I fail to see is the life cycle of directive.

For my purposes as described above I would be attaching the behavior to 
each item. From angular I get the creation phase which is good, but now 
when the list of persons change, I need to dettach the behavior instance 
from ghost HTML (and detach in genral, think for example when it has global 
event listening to close drop down or something).

So first question in my journey is how do I achieve that?

-- 
You received this message because you are subscribed to the Google Groups 
"AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to