In AngularJS, can/should I augment the model from a controller? - javascript

I'm very new to Angular and MV* in general (short of what I've gleaned from watching other devs work with Ruby on Rails for years), so please pardon what's probably a naive question.
I'm trying to set up a typeahead field where users can enter a street address and get live suggestions from the Google Geocoding API. I started verbatim with this example from UI Bootstrap (the "Asynchronous results" example in the middle field):
http://angular-ui.github.io/bootstrap/#/typeahead
It's working locally, but now I want to extend it to gather other pertinent details of the address and submit those along with the other form data. For example, if the Geocoding API returns a country type in address_components in its results (example here), I'd like to add that to the form data that I POST to the server. (There will be other logic to how/what properties I need to capture, but that's a good starting point.)
Right now, only the formatted_address property returned by the Geocoding API is submitted with the form, as the ui.bootstrap.typeahead directive binds that to the typeahead directive's <input> using ng-model.
So, my question is twofold (but please feel free to address either separately):
If I were starting from scratch (i.e., wasn't bound to the design/implementation decisions made in UI Bootstrap), what would be the most "Angular" way to implement this? Should the directive create an <input> bound with ng-model for every value I might want to capture, and then the controller would handle filling in the ones that are available?
Since I'm not starting from scratch, what is a reasonable way to augment the existing code to provide this functionality? Is there a way that I can add features to the existing directive? Does this behavior belong in the controller, or would I be better off abstracting it into a service? Or am I overthinking this - is there a simpler or better way that I haven't considered? Per the UI Bootstrap example, the only obvious place that I see to put this code right now is in the success function passed to .then() within $scope.getLocation(), where I'm handling the $http response, but my gut says that that's not ideal. All I can imagine doing there is adding properties to the form values object that I'm building (i.e., the object I'll POST on form submit), but then I have to know the names of those properties, so now my controller is tied too closely to the form in which it's used.
Thanks in advance for any help. I hope this makes sense. Since I'm still grasping the fundamental concepts, it would be especially useful if you could point me to any existing code that does something similar, or refer to specific documentation or articles that could lend some insight.

On #1, the Angular-UI design is a very "Angular" way to implement it - I don't see any issue with it. The directive takes a list and returns the selected list item. This is how the controller sees it. Put it in other words, another directive, say a typical <select> or a custom infinite scroll or a yelp-style map, would provide a different View behavior, but would be functionally equivalent from the controller's point of view - which keeps the separation of concerns intact, and thus very MVVM-y.
I also think that you have some confusion about ng-model. ng-model should be used with input controls (not only <input>) with which the user interacts with directly. In this case, the only input is a typeahead directive.
On #2, it depends whether the the "other pertinent details" are natural part of the service API or if they need to be fetched after selection. Assuming the former, the correct place is, in theory, in a service. The controller should only marshal data from Services to the ViewModel and back.
For your specific example with the country code, the API returns multiple components in address_components property. The extraction of the country code - as well as checking if it exists or not and other business logic - is best to handle in a service, probably with another service API after selection, or when the original list of addresses is obtained - whatever makes sense for your case.
For a simple case in a simple app, like in the example, you could just modify the $scope.getLocation() function to return a list of actual objects that your controller (or rather your ViewModel) actually needs, and then have the View return the selected object (as per #1).

Related

Django saving models by JS rather than form submissions?

I have a contract job for editing a Django application, and Django is not my main framework to use, so I have a question regarding models in it.
The application I am editing has a form that each user can submit, and every single model in the application is edited directly through the form.
From this perspective, it seems every model is directly a form object, I do not see any model fields that I could use for custom variables. Meaning instead of a "string" that I could edit with JS, I only see a TextField where the only way it could be edited is by including it on a form directly.
If I wanted to have some models that were custom variables, meaning I controlled them entirely through JS rather than form submissions, how would I do that in Django?
I know I could, for example, have some "hidden" form objects that I manipulated with JS. But this solution sounds kind of hacky. Is there an intended way that I could go about this?
Thanks!
(Edit: It seems most responses do not know what I am referring to. Basically I want to allow the client to perform some special sorting functions etc, in which case I will need a few additional lists of data. But I do not want these to be visible to the user, and they will be altered exclusively by js.
Regarding the response of SColvin, I understand that the models are a representation of the database, but from how the application I am working on is designed, it looks as if the only way the models are being used is strictly through forms.
For example, every "string" is a "TextField", and lets say we made a string called "myField", the exclusive use of this field would be to use it in templates with the syntax {{ form.myField|attr:"rows:4" }}.
There are absolutely no use of this model outside of the forms. Every place you see it in the application, there is a form object. This is why I was under the impression that is the primary way to edit the data found in the models.
I did the Django tutorial prior to accepting this project but do not remember seeing any way to submit changes to models outside of the forms.
So more specifically what I would like to do in this case: Let's say I wanted to add a string to my models file, and this string will NOT be included/edited on the form. It will be invisible to the user. It will be modified browser-side by some .js functions, and I would like it to be saved along when submitting the rest of the form. What would be the intended method for going about doing this?
If anyone could please guide me to documentation or examples on how to do this, it would be greatly appreciated! )
(Edit2: No responses ever since the first edit? Not sure if this post is not appearing for anyone else. Still looking for an answer!)
There is some terminology confusion here, as SColvin points out; it's really not clear what you mean by "custom variables", and how those relates to models.
However your main confusion seems to be around forms. There is absolutely no requirement to use them: they are just one method of updating models. It is always possible to edit the models directly in code, and the data from that can of course come from Javascript if you want. The tutorial has good coverage of how to update a model from code without using a form.
If you're doing a lot of work via JS though, you probably want to look into the Django Rest Framework, which simplifies the process of converting Django model data to and from JSON to use in your client-side code. Again though DRF isn't doing anything you couldn't do manually in your own code, all without the use of forms.

Angular.js Method duplication in controller when using service

I've created a BookService that is used for storing (add), getting (getAll) and removing (remove) books. Now I want to use this BookService inside my controller to publish some methods that I can later use in my view. My controller looks like the following:
app.controller('BookController', ['BookService', '$scope', function(BookService, $scope) {
$scope.addBook = function() { BookService.add(); }
$scope.getAllBooks = function() { BookService.getAll(); }
$scope.removeBook = function() { BookService.remove(); }
}]);
As you can see, the controller is just a proxy that forwards the method calls to the service. Is this in general bad practice? And is there a better way to solve that using Angular.js? Calling the service directly from the view without a controller seems, to me like a bigger problem.
Best Practice
From what I can see this is perfectly good practice, I'm assuming that you're using $scope here to bind these services to a button or something similar. The Idea of using a factory or a service is to create some well organised reusable code that you can then instantiate in your controller exactly like you have done.
Controllers can get quite complex so moving basic functionality to your service is the best thing to do. In your case you have a relatively simple controller so you may not see the benefit of coding in this way. But I assure you that as your code base grows you will be required to code like this just to keep things readable.
Note
Just as an extra note I've added a data process that you might take with an example of a database request
database > API > service/factory > controller > view
This would be the correct path to take when requesting something from a database.
What you have shown is not bad practice; it is in fact recommended that you abstract resource management logic (like adding, removing and finding resources of the same type) into a separate service, for organization and maintainability and reusability purposes.
I do understand from your example how the controller seems to be just a proxy to the service though, and why you would think it's repetitive and possibly redundant. Let me expand on your example to see if I can explain the reasons for abstracting the logic. In doing so, let's consider only the adding operation, even though the logic would apply to others as well.
Reason 1: adding a book (or any resource for that matter) in a web app is usually more complicated than just a bookService.add() call. It requires having some sort of form to enter the details, a submit button to handle the actual request, possible massaging of the entered data, adding new fields like time stamps and author ids, and persisting to some data storage. The first two or three of those steps would be applicable to the screen or view from which you are adding, so it makes sense to put that in a controller (the view model), whereas the rest of the steps should go into the generic service.
Now say you have another screen where you see a friend's list of books and you can add it to your list by selecting a book. In that case, the controller logic for that view's controller will differ from the previous example, but the service steps will still be identical, and thus do not need to be duplicated since the service can be injected into both controllers.
That's a big win.
Example 2: let's say you've already split the code between controller and service as describe in example 1 above. Then you decide that your data storage needs have changed and now you want to update your logic to save to a different database system. Now instead of having to change all the controllers, you just change your services and the everything works.
This is also a really big win.
Yes you'ved done this correctly. Just keep in mind that as you scaled up your app in complexity, you'll want to have isolated scopes, (and) decomposition into component directives. Each directive will have its own controller and template fragment.

Angular.js controllers

Note: Sorry for the length of the post, but the reason I decided not to break it down in separate questions was because I find these issues hard to address without a complex problem like this. I am dazzled, and a bit afraid, that I'm trying to force Angular to do stuff for me which is not the 'Angular way'. Any advice would be highly appreciated, and would probably get me on the right track with Angular.
My problem is as follows:
I have a dynamically generated form, controlled by myFormCtrl. I want to go extremely modular: I want to use it whenever and wherever. This means, that sometimes I'll need to put it somewhere as-is, sometimes I need to nest forms dynamically (like when I change a form value, and other sub-form appears), or control two separate forms as one in a view by a parent controller, with one 'Save' button for both. The myFormCtrl uses $scope.type_id and $scope.rowid to know, which record should it display from the database. The records are then Ajax-fetched by a service, and saved under the myFromCtrl's $scope.formItems. When saved, the form sends back data to the server (via service) with the type_id and scope credentials, so the restful api knows where to put the record.
In theory that would be really easy to do in Angular.js.
It definitely would be in every object-orientated language: The parent class could call a public method of getFormValues() of myFormCtrl. Now that can't be done in Angular: parent can't read children's scope.
For me, it seems, that this is not a simple 'how to communicate between controllers' issue. I know that the answer to that question is services, events, scope inheritance.
Also, a number of other problems seem to emerge from each solution I found sofar.
So I have a myFormCtrlBase class, which does basic stuff, and other more advanced classes extend this one. I also have a formControls.html, and a formLayout.html partial. The first contains an ng-switch, and gives the appropriate input element based on $scope.formItem.controltype, the second has the html layout of a common form, ng-including formControls.html at the right places. It utilizes ng-repeat="formItem in formItems", so that's where formControls.html's $scope.formItem comes from.
When I want the form to have a different layout for example, I create a customFormLayout.html partial ng-controlled by the myFormCtrl class.
First question: what if my form layout can't be put in an ng-repeat?
Like when form elements need to be placed scattered across the page, or form layout is not something which could be fit in an ng-repeat loop. my formControls.html still expects a $scope.formItem to work with. Easy OO solution: parent puts formItem in child's scope.
My solution: I created a <formItemScopeChanger formItemScope="formItems[1]"> directive which gets formItems[1] as an attribute, and turns it to $scope.formItem variable. This solutions feels messy: directives are not meant to be used like this. Doesn't seem very Angulary. Is this really the best solution?
Second question: Is ng-init really that evil?
Say, form is not put in the view by $routeProvider, but in a custom partial: rent-a-car.html. Here, I want to have a form where the user can select a car, and an other form, where I get his contacts. The two forms work with different $scope.type_id's, so there need to be two different forms:
<h1>Rent a car!</h1>
<div ng-controller="myFormCtrl" ng-init="type_id='rentOrder'">
<div ng-include="'formLayout.html'"></div>
</div>
<h2>Your contact information</h2>
<div ng-controller="myFormCtrl" ng-init="type_id='User';rowid='{{userData.rowid}}'">
<div ng-include="'formLayout.html'"></div>
</div>
Angular docs sais, that the only appropriate use of ng-init is when aliasing ng-repeat values. I don't see what the problem is with the example above - it is still the cleanest solution, isn't it?
I use the same technique with nested forms - I put a controller in with a template, initialized from the html by ng-init, and shown/hidden with an ng-if condition.
BTW, this is the only real initialization technique I found beside writing a new controllers (extending myFormCtrlBase). In an OO language, parent would write into the child's scope and then initialize it.
Perhaps my approach is influenced by my previously used languages and programming techniques, and is absolutely wrong.
Some would say, 'get init values from parent scopes!', but I can't seem to understand how that would be safe and efficient. I'd need to do $scope.type_id=($scope.type_id || $routeParams.type_id) with every scope property, which is first: really not nice to look at, second: is risky. Maybe this is a single form in a simple template, but somewhere in the scope hierarchy, there is a possibility, that it will find a completely different type_id. Perhaps it will be a completely different controller's type_id.
I don't see how using '.'-s in my scope variables would help. I has the same risk as I see it.
Third question: how to handle rentACar.html submission?
When hitting a Save button on my rentACar.html page, the rentACarCtrl (the controller in charge of the model of the view) should somehow retrieve the values of the two forms, and handle the validation and submission. I can't seem to understand how the common mantra 'controllers communicate through services' would be applicable here. A service for only to these two forms?
Am I on the right track? Every one of these solutions seem quirky. I feel lost :)
+ 1 question: Even after all this hassle, I can't seem to find a good reason why Angular wouldn't let parents call children's public stuff. Is there a good reason? Most of the above problems would have an easy answer in every true OO js framework.
You need to think about how you would test the logic of each of these components. Ask yourself how each of these 'features' work in isolation.
A few tips to help get you back on track:
Try and say away from a 'base' controller, I have hit many dead ends with scope inheritance, the logic gets muddled and hard to follow. Also this affects testing, because you find yourself having to stand up more objects than should be necessary for a test
Favor a singleton (angular service) for shared state over scope inheritance (a parent controller)
Create a directive and bind to the shared services state before using ng-include (prefer interacting with a service over scope inheritance)
Use an event pattern when another service or controller needs to now about events triggered from directives. A shared service (state) can listen for those events
What your asking is quite complex and I would like to help, Try to focus on one feature at a time and provide some code, I can show you how to use a shared service and the event pattern once you provide some examples
Also, taking a test first approach will often reveal the best 'Angular Way' of doing things.
Thanks to Mark-Sullivan, and a lot of work, trial-and-error attempts, the whole thing has boiled down to this. I'd like to get feedback from Mark, and other Angular gurus about this. What do you think?
You don't do class/prototypical inheritance in Angular.js. It is hard to test, and thats a big problem. For those, who are looking for 'inheritance' in Angular, I recommend this:
Your base class is the controller. The controller is an abstract model anyways, so it is perfect for that purpose. Use a $scope.init() function in your controller, but don't call it from there!
If you want to 'extend' your controller's functionality, use directives. In you directive link() function, call the controller's $scope.init(). (when compiling, angular runs controllers first, and directive link functions after). If scope had a $scope.name='base', in the directive link you will be able to redefine $scope.name=child, and after that, run $scope.init().
But wait! But this only allows a single-level inheritance. - Yes, thats true. But if you are looking for multilevel inheritance, you should use Services.
Multilevel inheritance is nothing else, but sharing the same code in a hierarchical class structure. For this purpose, use Services, and throw in these services with the dependency injector into your directives. Soo easy. This should be easy to accomplish, easy to understand, and tests run smooth.
Directives are very powerful tools, because you can dynamically combine partials with controllers.

mvc approach with javascript / jquery no framework

I'm developing a large scale application. Initially my approach was confused , I am a beginner in javascript even if I develop since January.
I was looking for an mvc approach and I found some guide lines, like :
Model : contains AJAX call , and services
Controller: e.g. jQuery widget and so on
View: e.g. rendering of HTML and so on..
I don't really have clearly how to structure a javascript application following perfectly the three above suggestions. I can do everything, I can manage template I can write jQuery manipulation , I can do AJAX call.
What is not clear to me is how to get really divided these three modules. When I try this approach I'm not able to make any module to do only what it has to do.
I tried also an MV* approach which, for what I see and for my needs maybe it's a better approach, because I have to do bind tons of divs , generate events , all by client side, receiving only data from server side.
What I would like to know:
Which are the really competences of each Module?
If, for example, I have to bind a click event to a button , where do I have to write the
.on('click',callback)
method? Where I have to write the callback he's gonna call?
I wrote : no framework because I'm sure that if I don't understand an approach writing it from scratch, its impossibile I will completely understand the use of a complete framework.
I hope that my doubts were clear, if not, please comment, I'll try to explain better if I can.
Sorry for my english in any case.
This is not an answer because there is no one answer. I just want to mention a few do's and don't's.
Do store pure data in the model. Think of it as business objects rather than display objects. For example, money should be stored in the model as a number, probably with some digits after the decimal point, plus an indicator of what currency it is, if that matters. Don't store the number as a string with local choices of the characters to separate the 1000's and the integer part from the fractional part and the right number of digits after the decimal point.
Do put the handler code for the click events (and similar user actions) in the controller.
Do put the code that causes updates the screen on load or on any external event in the controller. (An external event might be something like an update to a stock price due to stock exchange data or an update to the weather report coming into the application.)
Do put the HTML or the code that generates HTML as part of the view.
Do have the controller call the view to get the display updated/changed at the right times.
Do have either the controller or the view call the model to get the current model data values or the update the the current model data. (See similar "don't" below.)
Do reduce the connectivity between the three parts--M, V and C. Define clearly who can talk to whom for what purpose and keep that rule sacred. If you find an exception, its a smell indicating a problem with the big picture of those rules.
And some more things
Don't put the code that displays the screen on load in the controller. That's clearly a view concern. This means the controller has to call into the view somehow.
Don't spaghetti connect the M, V and C code in random fashions. For example, you might make a rule that the model never calls code in the view or controller.
Don't have both the controller and the view talking to the model.
Questions:
Where does the code go that hooks up the event handlers?
Where do you put the "business logic"? This is the code that knows the rules of your application. Validation, for example, is business logic. Some code may need to know how zip codes look for the US and postal codes for the UK or Canada. If the validation fails, the controller is the one that tells the view to show an error message or red mark or vibrating box or whatever. Does the business logic of validation rules also go in the controller?
Where does the code go that loads data from external data sources? (servers, JSON web services, databases, screen scraping, etc.) You might think "model" but then the model has to call into the controller when new data comes back to tell it to update the view. That doesn't seem right.
Similarly, what is the code that handles the equivalent of a "submit" button, moving to another screen.
If converting data from a form that is displayable on the screen to a form that is pure data is too slow, what do you do?
There are always self-contained portions of the screen that can be built with their own MV&C. How do you set up interactions between multiples of those little MVCs and the big MVC that is the whole screen? Are those little guys the views for the big MVC? Or are the controllers? Can they be both at once? Is there a big model with the little models in it or does data flow between little models and big models? Who knows about all this?
Is there an even bigger MVC comprised of multiple screens? It would probably be on the server if it exists.
How do you handle "synthetic" events? This is something like an "event" that occurs when the data was ok but is now in a bad state (or was incomplete and is now complete). Listeners to this event can disable the "Submit" button and display error messages or animations calling the user attention to the problem. It could be anything that isn't a generic event built into the framework or language. Perhaps its a message to the server indicating a change in the state of a multiplayer game's world view.
This is just a list of things that pop to mind when you are writing your own MVC or when evaluating an existing framework.
There is no clear answer outside a specific framework. Although the general responsibilities of the MVC pattern are (almost) clear to everyone, each framework has its own interpretation of exactly what pieces of code to put in each of these layers - some frameworks even skip some layers, or add different ones instead.
I know you don't want to use a framework, but still, it's worth to have an overview of how the current solutions work, so you can make an informed decision if you like the way they work or if you prefer to roll your own.
I recommend you at least take a look at one server side MVC framework (such as Ruby on Rails or Asp.Net MVC) and some client side MVC frameworks too (Backbone.js, Angular.js, etc. - javascript only). Read their documentations, and learn from the choices others have made (and tested). The site todo mvc can help you to compare different client MVC frameworks to find the approach you like better.
This is not a simple topic, and discussing the pros and cons of each approach from scratch can take forever.

Javascript MVVM design patterns - how to track dirty state and who should do Ajaxing?

I'm part way through a pretty complex Knockout.js app using the mapping plugin to work with a deep object graph which closely mirrors server side domain objects. I've been refining my patterns as I go to something which works pretty well for my own slightly awkward context but I'd like to know if it's a good / bad overall way to approach MVVM Javascript.
Essentially my page pattern is to have a revealing module function which acts a bit like a controller - it owns the hierarchy of view models and is responsible for detecting changes, Ajaxing changes to the server and using the mapping plugin to update its view model graph with any flow-on changes which may come back in the response as JSON. I've done it this way because my domain is such that a small change in one part of the graph, when validated on the server, may result in changes / removals in distant parts of the graph. When this happens I need a common point at which to re-map the changes, present message dialogs to the user, etc.
All of my view models are instantiable functions and I've designed it so that they know nothing about the page they're used in, or the server (i.e. they don't do their own Ajaxing). The constructor of each view model creates its children via mapping options and each level is passed a reference to its parent. I've implemented a generic dirty flag which most of the view models use, and when a change occurs they pass a reference to themselves up the chain to a "dirty view model" observable at the top, which the module is subscribed to. I know this sounds a bit odd but it seemed the best way to approach it because items at each level are constantly being added and removed so I can't statically subscribe to properties at initialization time. And I don't want to keep removing and re-adding subscriptions each time I re-map my graph (which can get quite big).
From a pure efficiency point of view this isn't the best. The simplest way would be that each view model directly calls a function in the module when it needs to, but that type of coupling has to be wrong. Or I could pass in a reference to the module (or its relevant function) to each view model constructor, and the view model calls that, a bit like Javascript dependency injection. But that just seems too abstract. This is complex enough as it is.
Should I be looking at a higher level framework such as Backbone to sit on top of all this? Is injecting the module reference really too abstract? Or does this way of structuring things basically make sense as it is? I'm keen to hear from anyone who has worked on similarly challenging scenarios as to how you progressed and refined your patterns.
EDIT: I should have clarified that for various reasons, this app works in "save as you go" mode, whereby a change at a given level causes an immediate discrete Ajax post of just that one view model (not including its children) to be sent to the server (which may return a result which represents a change to just about anything else). Despite this annoying need for constant Ajaxing as opposed to pure client side action, Knockout.js has still made my app WAY more elegant, maintainable and scalable than my MVC apps of Olde.
Decoupling your viewmodels and reducing references can be achieved with a pub/sub model, like the one Ryan Niemeyer discusses here.
Ryan also made a Dirty flag for viewmodels, which can be found here.

Categories

Resources