I’ve been searching for the best way to handle modals in angular and I'm getting the impression that they need to be separated from controllers in order to achieve separation of concerns in MVC.
However when it comes to implementing this using a directive or a library out there I don't see the need for such massive overhead of adding so much code. Effectively it seems as though we are doing exactly the same thing but with more calls and events kicking off as compared to directly showing a bootstrap modal in the controller or service using jQuery as easy as:
$scope.saveChanges = function () {
$('#messageTitle').text('Done');
$('#messageText').text('Changes have been saved.');
$('#message').modal()
}
Porting a directive to handle the dialog is in effect showing the modal with additional steps and setups between dependencies etc. within angular, external libraries and/or custom code (whichever way it is applied). It's really like having a more simplified method call to a utilities method in some utils file that will just show the modal using jQuery. Again, I would be enlightened to know why this is not case which I expect from more experienced angular experts.
Apart from the fact that it is assumed a correct working way to do it, is there a reason why the DOM should not be referenced inside a controller. Could it have an effect on things like i.e. performance, buggy code, testing etc.?
I know that because it makes test cases easier is one of the reasons. Again, a valid reason however testing is not much of an issue having the DOM in business logic as in the code above if tested right. If there are, even more pressing cases for this, what are they? If any what is the best and most efficient way to achieve separation of the DOM from controllers/services if the same applies to services?
Background into current explanations:
What's the correct way to trigger jQuery DOM Manipulation from within a controller?
Separating DOM manipulation from Angular controllers - Best Practice wanted
AngularJS - why manipulating DOM in controller is a bad thing?
Why is it considered a bad idea to manipulate DOM in controllers?
From my understanding, these are the main reasons why a controller should not manipulate the DOM:
Testing. Test cases or test steps can be made well-structured and very easily testable when testing logic in controllers. Here what is tested is truly what a controller should be responsible for (Model manipulation).
Applying well-structured MVC code at the angular code base. Separation of concerns again gives a plus mark for testing but also makes code more manageable and well structured.
I would be happy to hear more detailed alternative answers to completely confirm and explain that any DOM manipulation what so ever is a bad thing within a controller. On the contrary it would be interesting to know whether there are exceptions. For the information of others and my attempt to answer, the reasons above are the most commonly known reasons and thus probably the only reasons to my knowledge, which fair enough are acceptable reasons at this point.
Related
I know it is bad practice to have the DOM manipulation in anywhere other than directive. but I do not understand why is it a bad practice to have the DOM manipulation in the service/factory as we can reuse them.
I have searched online and also found the same question on stackoverflow
stackoverflow question
but still not clear with the answers.
Angular follows declarative principle which means
a style of building the structure and elements of computer
programs—that expresses the logic of a computation without describing
its control flow
At the same time services in angular were introduced to contain business logic. If business flow is complex - imperative approach suites better.
In such a way if you have DOM manipulation in the service you probably violate separation of concerns principle, as you are coupling UI and business layers. And coupling itself eventually ends up in spagetti-code when this "reusable" components (according to new requirements) should look a bit different in the modules where they were integrated
Directives, by definition, are always attached to a DOM node. So when we create a directive, it either expands or replaces the DOM node.
services are engaged with directives so we are able to manipulate view of an app through directives. however, there are cases where you might need to manipulate DOM element(s) via a service, like in a modal window.
I have a rule of thumb for situations like this. can DOM manipulation be done directly with the attached node? and answer to this question tells me if I need to use a directive (yes) or a service (no) but overall it depends on complexity of your project as well.
Its common knowledge that DOM manipulations should not be performed in AngularJS Controller, its very hard however to find why exactly is it a bad thing. All the sources say its difficult to test and because controller should be used for communication between directives, but fail to illustrate with code why this is a bad thing.
From my understanding I would think that controller, unlike directive, is not associated with any specific HTML, hence all the DOM modifications controller would do would very possibly fail. This would sure complicate development and testing.
Controller in directives being executed before link functions of child directives would also fail as the controller might not be aware of what the actual HTML of the child directives is. Link is executed after controller function and might modify HTML structure.
I hope I make sense here and if someone could clarify why manipulating DOM from controller is a bad thing, maybe some code exampleor link that explains it well that would be great.
The reason it is more difficult to prove their point with a code sample is that the reason can't really be represented by a short code snippet (short enough for Stack Overflow). It is really a maintainability precaution. Over the long term, you want to be able to independently alter the logic behind controllers and views independently, because otherwise a coupled controller and view pair tend to stay that way and limit each other in their ability to change their functionality without breaking the other. As soon as you decide to change anything about the view, you have the chance of making your controller code break without even touching it.
Testing becomes easier over time because the more tests you have, the more you wish that things were more modular and dependent on as little variables and parameters as possible.
Again, it is maintenance that drives this suggestion. The problems listed above might not be that bad starting out. But imagine adopting a project that you didn't build from the ground up and know all the intricacies behind the coupling between controller and view that hold this application together. What if your application reaches so many thousands of lines of code that it would be impossible for you to know all these intricacies even if you DID build it from the ground up?
For a more general understanding of why design patterns like the one you have alluded to are necessary, you can refer to this google search that will take you on a journey as long as you are willing to take. And for a general understanding of why design patterns even exist and why many people end up suggesting the same thing over and over again, you can refer to one of the catalysts to the introduction of design patterns, Christopher Alexander. He shows us that patterns are what they are because they work well and people repeat what works well.
If you look at the ever so popular question "Thinking in AngularJS" if I have a jQuery background? you will get some hints.
One of the biggest factor that i think DOM manipulation is neither needs nor done is because Angular uses declarative approach when it comes to DOM linking as against the imperative approach that you would use with direct DOM manipulation. Some of the answers detail this difference between declarative and imperative approach.
With jQuery you tell the DOM what needs to happen, step by step. With
AngularJS you describe what results you want but not how to do it.
More on this here. Also, check out Mark Rajcok's answer.
A more comprehensive treatment of this topic is also available here What is the difference between declarative and imperative programming
With such an approach the controller implementation is simplified, and we start to get real value as code base size grows and complexity increases.
My perspective is bit different and covers more than testing. It is the ability of the designer to have control over the HTML layout that otherwise would be taken over by writing code inside of the Angular Controller. Consider the following snippet (it is just a simple example)
<div ng-repeat="article in articles">
<p class="article-body">{{article.text}}</p>
</div>
This example just iterates over a collection and prints article in a separate paragraph tag. While it is certainly possible to loop over the collection in an Angular Controller and dynamically generate paragraph tags with text inside it. It will take away designer's capability to modify look & feel. Hence, If there is a requirement to show the article title, instead of doing this
<div ng-repeat="article in articles">
<span class="article-title">{{article.title}}</span>
<p class="article-body">{{article.text}}</p>
</div>
the designer will now have to locate Angular Controller code to modify DOM manipulation. Just compare above two approaches and guess which one will provide more flexibility.
I have been wondering whether I should be using JavaScriptResult?
I have read couple articles about this and people have contradicting opinions.
I can see benefit:
Code is rendered in controller and therefore I can interact with my data sources and more difficult calculation and logic.
But JS rendered based on page using rendered jasonresult seem to be better choice.
Not sure about programming pattern:
How does JavaScript rendering in controller fits with Model View Controller
MVC is the design pattern which is all about separation of concern. I often hear that JavaScriptResult is something to avoid as it breaks that princple. In my opinion you should keep that in mind that MVC gives you powerful tools but it's up to you, what will you do with them. JavaScript XHR / Ajax can deliver more than only GUI renderring, but should be used with consideration. Well, fact is one can missuse even the simpliest methods, but that doesn't mean we shouldn't use them :)
Of course, using JavaScript on your page, and feeding it with JSON is perfectly fine and prefferable, in most of the cases it's sufficient. Sometimes though, you will need to choose wether you want to be 100% compliant with MVC pattern or DRY principle / other good practices. I think it's best to do what you think makes sense in a particular situation.
Let's take WebGrid helper's GetContainerUpdateScript method http://msdn.microsoft.com/en-us/library/system.web.helpers.webgrid.getcontainerupdatescript(v=vs.99).aspx it delivers jquery oneliner to update your webgrid data. In this case it's all in the View, but similar code could be a part of the controller - let's say a script that makes bunch of POST requests based on some unique identifier (sessionID-like for example).
In my opinion there are worse things than stepping on a thin red line between View and Controller (and sometimes crossing it slightly) to avoid other problems, make your code cleaner, more reusable and maintainable.
For example if you write a plugin you could do this $('#myDiv').doAction() instead of doAction($('#myDiv')). and you have to admit, the first one looks more intuitive. Are there any clear drawbacks of this like performance hits?
You won't see any noticeable performance hit from this, but there is one potential drawback: namespacing your code is very valuable, and makes it easier to maintain (as you probably know). Throwing everything into jQuery.fn may not be the best way to do this.
Personally, I shy away from extending jQuery with very specific things (like app-specific logic or something) but whole-heartedly recommend it for general, DOM-level things (.hasAttr() and .scrollHeight() are two I use a lot). The reason is that there are better places to put app-specific logic (in the module in charge of that area of the app, for example).
A simple heuristic: would it be useful to other people if I made this a public extension? Or is this only relevant to this particular project?
That said, there is no concrete problem with doing this in your code. It's more a semantic issue: is that the best place for it?
Write a jQuery plugin so that you do not need to repeat this over and over again.
There are literally minimal performance issue with this, and mindful that this is at client side, it does not attribute to your server resources.
There aren't any performance hits choosing one approach over the other. It's more of a question of, do you need it as a jquery plugin? I create regular functions if it's a utility function and doesn't need to act upon a jquery object. If it does, then it should be a plugin (no need to pass in the jquery object as a parameter, and you can chain)
You seem to be using jQuery as a framework. It is not one.
Please use a client-side MVC style library like backbone/knockout/sammy/eyeballs for seperations of concerns and structure
Please use an AMD loader like curl/requirejs for modularisation of your code.
This sounds like a stupid question, but thought I would post anyway...
I am just making a simple web app with javascript and html and decided upon Knockout JS for the main framework to manage the UIs. However I am a bit puzzled how to proceed.
My first page is a very simple login page, it just has a username and password box, the problem comes when I want to do thing with the UI. An example would be adding a watermark to the ui boxes, or adding logic around listening to custom events, I could just write it as in-line javascript but I cannot really unit test any of it then.
Originally I was planning to use an MVC style pattern so I could unit test the controller with a mocked view, and just put any ui logic in there.
So is there any acceptable way of doing this without putting it all as in-page logic?
The way mvvm works is that the view should pretty much be a visual representation of that view model, so put your logic in there. If you design it right so your functionality is contained in seperate classes then you can mock them all out easy enough. If you are used to MVC then just see the viewmodel as your controller.
I can see where you are going with your question though, as with complex views you could end up with quite a lot happening within your ViewModel class, but if you just stick to simple oo and encapsulation principles you wont go too far wrong...
So anyway to summarise, put it in your logic in the view model.
There are two approaches you can use. There is an xUnit package for JavaScript called JsUnit So it is possible to unit test your JavaScript-based UI logic. The other route as you mentioned is to use the controller to contain the logic and the JavaScript as a "pure" view model. I personally feel that either approach is viable. You just want to make sure that your JavaScript-based view model doesn't become too intimate with the view. :)