58

I just started to learn AngularJS and struggle with some concepts of AngularJS. It would be great if somebody could explain me some points...

  1. I understand that ng-click is technically not the same as onclick (see here), but both are placed in the markup. I thought that would be a "bad practice"? Why is this one of the core concepts of AngularJS, if most people say this is "bad"? I thought it would be better to select the DOM element from JavaScript and not to place logic in the markup.

  2. If ng-click is the right way to react to click events in AngularJS what should I do with other DOM events? I see that there are several other directives like ng-mouseover, but not all DOM events have a AngularJS equivalent. How would I handle a 'drop' event in AngularJS (hence in the AngularJS way - not the normal way)? To be clear: I want to drag a file into my webapp.

Thank you very much, Pipo

Community
  • 1
  • 1
Pipo
  • 5,623
  • 7
  • 36
  • 46

2 Answers2

54

Why is this one of the core concepts of AngularJS, if most people say this is "bad"?

Well, people who really like Unobtrusive JavaScript might say it is bad. Angularians (and those with a flex background) see value in the more declarative approach.

"Angular is built around the belief that declarative code is better than imperative when it comes to building UIs and wiring software components together... By declaratively describing how the UI should change as your application state changes, you are freed from low level DOM manipulation tasks. -- Overview doc

See also Don't the data attribute options used in Bootstrap, Angular.js, and Ember.js conflict with Unobtrusive Javascript principles?

what should I do with other DOM events?

Write your own directives to listen for them (or find one that someone else has already written). Angular gives you the power to extend what the browser can do -- by writing your own directives.

Update: in the comments below, Tim Stewart mentions AngularUI's ui-event, which lets you bind a callback to any event not natively supported by Angular.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 2
    +1; it all has to do with context. In an Angular application, the view declares how the user interacts with the application, and since the view is HTML, that's where `ng-click`, et al. go. In other applications and frameworks, that is not the case. – Michelle Tilley Jan 16 '13 at 06:02
  • 1
    Thank you very much for your answer so far. One last question: Isn't it a major drawback to write my own directives for "missing DOM events"? This doesn't seem to scale well. – Pipo Jan 16 '13 at 07:48
  • 2
    @Pipo, I don't see it as any different from writing your own jQuery plugins to accomplish what you want in jQuery land. I don't quite understand the scaling part... Directives we write are no different from the directives that the Angular guys wrote that come built-in. In [this 10-min video](https://plus.google.com/+AngularJS/posts/6DjeAMwXco7) Igor even said that you can rewrite all of the built-in directives if you wanted to. There are no inherent speed or scaling advantages to the built-in directives vs directives we can write. E.g., the same Angular compiler parses both. – Mark Rajcok Jan 16 '13 at 15:16
  • 2
    @MarkRajcok: I think it is a little different. When I use jQuery I can get all my "jQuery power" and can use all "DOM events" with ".on({eventName}, callback". I don't have to develop a jQuery plugin to use all DOM events and get the advantages from jQuery. On the otherside there is no "ng-{eventName}='callback'" in AngularJS (At least not for all events). Therefor I don't get the benefits from AngularJS, if I don't write a custom directive. – Pipo Jan 16 '13 at 15:32
  • 3
    @Pipo, true, Angular doesn't pack the same "event power" out of the box. However, in Angular apps we normally $watch $scopes/models/data for changes, which trigger callback functions, rather than watch for events, which trigger callback functions. So I guess one could say that Angular has "model power" instead, and there is therefore _less need for "event power"_. Angular: change data models and let views (declarative HTML that contains directives) update/change (the DOM) "automatically". jQuery: register events, which trigger (imperative) code you've written to update/change the DOM. – Mark Rajcok Jan 16 '13 at 15:53
  • 8
    @Pipo - someone already did if for you - check out ui-event in AngularUI, lets you bind to any DOM event: http://angular-ui.github.com/#directives-event – Tim Stewart Feb 11 '13 at 03:56
  • @Tim: Great. Do you know if this works for all (future) DOM events by default? EDIT: Found it: "Bind a callback to any event not natively supported by Angular." – Pipo Feb 11 '13 at 08:49
5

By nature, Angular requires elements in the markup in order to function properly. Further, those elements must be "compiled" each time they change, for the most part. So, it's already somewhat "obtrusive" irrespective of the JavaScript. You can't simply replace the markup, and have everything auto-bound for you like you can with something like jQuery.

Strictly speaking, unobtrusive JavaScript: 1. separates structure and behavior, in order to make your code cleaner and script maintenance easier 2. preempts browser incompatibilities 3. works with a clean, semantic HTML layer (Wikipedia)

That's not Angular, for sure. In order to achieve the two-way binding on everything, they chose to make custom binding points in the DOM, as opposed to using a class name or ID the way that jQuery would do. (A somewhat non-standard approach, but it obviously works.)

But the real way to think of it is this: Basically each controlled section of your markup is not really straight HTML anymore anyway. It's really more of a template now, and as such requires interaction with the engine that is preparing it for rendering. As such, the traditional rules of unobtrusiveness don't really apply... (FWIW, I'm a huge fan/user of the jQuery.on() function to bind elements to events automatically when the element is added to the page. Very clean and flexible, IMHO, and I do wish there was a similar mechanism in Angular. I like adding a class to items in multiple locations on the page that invoke the same event handler automatically. Having a single place to go change code is a good thing. but I digress...)

For me, the bigger issue is that of progressive design. Does the web page work without JavaScript enabled at all? Does anyone really care about that? Hmmm...

Craig
  • 150
  • 2
  • 6
  • Coming from a Microsoft-MVC-UnobtrusiveJS background, this answer helped me understand Angular a little better. – Lunster Jan 02 '15 at 10:42
  • AngularJS (and ReactJS) are obtrusive javascript frameworks which couple the static data layer (HTML) to the logic (Javascript) needed to process that data. This is bad practice. You're essentially locking your developers into a Google (or Facebook) product. Example: You spent 2 years writing an AngularJS app, and now you want to move-over to ReactJS because it has faster performance. If you had decoupled the logic from the data, you could reuse your HTML templates. But, now you're stuck in continuing to use AngularJS or rewriting your entire code-base with ReactJS. – tim-montague Feb 08 '15 at 23:16
  • WIth good DDD, conversion to/from Angular is easy. For gaming level performance, neither Angular nor React is the right choice; I would be rolling my own. But Angular was built for two-way data binding. Since time to market can be as important as how fast your application runs, Angular has some serious advantage here. Angular 2.0 promises HUGE performance improvements as well. Plus TypeScript compatibility. – Craig Mar 18 '15 at 21:20
  • @tfmontague React does not couple HTML and JS. JSX in React components looks like HTML, but turns into instructions to build the DOM. React *can* be used to generate HTML with renderToString() or renderToStaticMarkup(), which can be used to make "unobtrusive JS" sites, though that does get tricky. – Max Heiber Oct 25 '16 at 20:32