Cordova - Angular - <select> tag open a new view - angularjs

I have an Angular/Cordova app and I'm trying to figure out how should I handle the HTML SELECT tag. What I would like to do is to open a new window with all the options in a list, the user picks one and returns with that value.
The problem is when I do that I lose all the data I had in the first screen as I am closing it when I move to the second one.
I am using Angular's UI.ROUTER. One thing, which I am not too convinced to do, is to save all data entered into StateParams, and when I return, place it back.
What would be the best approach?

It really depends on the use case. If you need to be able to "deep link" to the view where a link loads the view with the pop-up active then using ui-router and stateparams makes the most sense. If deep linking isn't a concern and the user must always select something then you can just use a service/factory/value/provider in order to share the data between the controllers during the lifetime of the app.

Related

Calling a view controller from index.html

I have an index.html that has a top bar with links and a side bar with links. I want the center to be replaced with content (ng-view). Let's say the top bar is Pictures, Stats, Chat. The side bar is Tigers, Lions, Bears.
These never change. This is why index.html holds them. The top bar of Pictures, Stats, Chat I want to actually route to different views/controllers (replaces ng-view on index.html). Easy.
However, when inside a given view controller (let's say Pictures) I now want to know what side bar was clicked (I would like to default to a given side bar animal when Pictures is first clicked in the app since that would be required) and I'd also like to be able to copy the link directly to there (ie Pictures/Bears (but this always just goes to the Pictures controller but inside there I know Bears was clicked so I can act accordingly)).
So if I click Tigers, the controller will know this and I can code it to get pictures of Tigers.
I don't want to put that side bar into each page itself since it's always the same. I just want it on index.html to avoid repeating myself even though this would be more direct in terms of coding each top bar view. This would be something I'd fall back to in the case of what I'm asking to do isn't possible.
I'm also wondering if it's possible to maintain the current side bar value when they click on a different top link animal. So if I was in Pictures/Lions and they click Bears, it would know to route Pictures/Bears. Since it's staying in Pictures would it really even need to route? Can it route and then call a method on the Pictures controller passing in the animal so it can do what it needs to with that information?
Try making a service like animalService that keeps track of the selected animal. This will act like your own route handler for just that side menu.
The controller for the side menu would then be able to call animalService.selectAnimal(selectedAnimal) to update the selection.
Each main page controller could then watch the value of the selected animal from animalService. There are a few ways to do this, but it would probably be easiest to use a subscription based approach:
Each controller would call animalService.subscribeToChange('controllerName', callback) on initialization and then on destroy it would call animalService.unsubscribeFromChange('controllerName'). The animalService would keep a list/map of all of the subscribed controllers, so it can execute the callback every time the selectAnimal function is called and detects a change.
If you provide a code sample I could try to give a more detailed solution.
Alternatively
You could take advantage of $rootScope. I find this a bit more hacky, but it would be probably quicker to implement. The side menu can access a root scope variable via something like $root.currentAnimal, and it can both get and set that value. Then each controller can use $rootScope.$watch('currentAnimal', function() {}) to trigger something on change ($rootScope is a service).

is it right to do using ui-router to activate menu items. Any advices to help me understand this?

What I did is:
When a menu item is clicked, a action will be done, like deleting a user, sending emails to a group, etc. To this end, for each menu item, I define a ui-router state, and use the state url to activate the state via sref. I thought that a menu action is just a UI component for user to let users to do something, which is just a state of UI.
I was advised that I was using ui-router in a wrong way as a state url can not identify an action. For example, to delete a group of users, the state url can not tell you what group of users have been deleted.
In short, I agree with your manager while being an angular newbie myself. Angular routes are designed for managing different views of your app. I.e. define a route and corresponding view template for each view. If you add application logic into the routes, your application structure gets quickly a mess and difficult to keep clear.
To me it is much more natural that the views are managed by the routes, and each action in each view is handled by the controller of that view. If the actions grow "big", then it is worth refactoring parts of the controller into separate services. If you require some sort of "dynamic HTML" depending on the action, e.g. bootstrap modals are handy for doing that within the current view (see http://angular-ui.github.io/bootstrap/).
E.g. in my current project, I don't actually manually edit the routes at all but let yeoman angular generator to do that for me free of charge - i.e. I instantiate each new view in my dev.env using the following command (more info on this from https://github.com/yeoman/generator-angular)
yo angular:route myNewView
More info on angular philosophy can be read from angular documentation for developers: https://docs.angularjs.org/guide/concepts
You should probably be doing this actions via a method on $scope.
$scope.deleteItem = function (items) {
Service.delete(items);
};
// which is the same as:
$scope.deleteItem = Service.delete;
<a ng-click="deleteItem(item)">Delete This Item</a>
Having it in the URL just seems wrong. I mean what does that look like? www.mysite.com/delete/users?

AngularJS: ng-model not getting applied on Controller instantiation

I am creating a web app planner using Angular and I am having some difficulties with a <select> box that is not changing value based on the variable denoted with ng-model.
My architecture is as follows:
I am using ui-router which gives me different view states, one for each page of my planner. The root HTML page has a Controller called MainController. This is where I set up my JSON model, $scope.Master = {} that I want to use throughout the planner. All pages of the planner should inherit this model and continue to modify/add to it.
I then have my 4 pages of the planner like:
Start -> Accounts -> Settings -> Review
Each page has its own Controller that gets instantiated every time I visit the page. On the Start page, I have a <select> box that has ng-model="$scope.Master.Start.selectedAccount" that gets populated dynamically using the StartController (therefore it gets populated every time I come to the Start page).
This <select> works great on the first time to the page, but if I go to Accounts and then come back, the select box is back to the default value, "Please select an account", instead of the selected account that is in the $scope.Master.Start.selectedAccount model that is bound to the <select> box
I thought I could just do something like $scope.$apply or something in order to re-apply the binding to the DOM object, but that just gave me an error saying it is already digesting.
How can I apply the binding to the <select> box after the page has been loaded 2 or more times?
This is probably because every time you go back to your original page, a new controller is instantiated since it was removed from the DOM when you left it originally. Thus $scope.Master.Start.selectedAccount. To save this, you can either
Use a service / factory singleton on the main app to save this value
https://docs.angularjs.org/guide/services#!
Save $scope.Master.Start.selectedAccount as a global variable
https://docs.angularjs.org/api/ng/service/$rootScope
Put that controller on the outside
Im real sorry... I realized I was populating the <select> using ng-repeat instead of ng-options no idea how I managed that... That was the problem

Many active states simultaneously with ui-router

What would you like to be able to do for example is:
I have an active state 'order.detail' in shell, in these details would provide a link in each product line that leads to 'product.detail' state that is also a state that can be displayed in the shell.
But this link should display the state ' product.detail' as a frame in a dialog without changing the current location and maintain active state in the shell intact.
Also the 'product.detail' state, to be used as a main view of the shell, and to allow their reuse, your template should be wrapped by 'div' template of dialogue.
What I mean is, allow consult the details of something without leaving the current screen, and do so using the same existing details screen, or simply allow the 'Drill down' by related data with existing views.
Sharing state in AngularJS
One of the great things about Angular is that's it quite easy to keep track of state via providers.
For example consider one index view containing a paged grid table with many filter options. Clicking on one of the entries will take you to details view of the entry. When the user goes back from the details to the index he/she will expect that the UI state of the grid will be exactly the way they left it: same page, same sort by, same filters applied, same everything. With traditional techniques you would have to fallback on cookies, query params and/or server side state(less) magic, which all feels (and actually is) very cumbersome and error prone.
Provider values are singletons in the world of Angular, so when we inject the instance in one of the controllers, it will always be the same instance. Controllers on the other hand will be recreated each time one is requested.
Example
Register an empty object to keep track of controllers:
myApp.value('formState', {});
Create a controller, inject the provider value and expose it on the scope:
myApp.controller('MyController', function($scope, formState) {
$scope.formState = formState;
});
Hook any property of the provider value to input elements via the ng-model directive.
<input type="text" ngModel="formState.searchFilter"/>
Now every time the user will leave and re-enters this view the state of the UI is kept intact. You can add as many data to the state as you see fit and maybe even share it among multiple controllers if needed.
Provider types
There are different ways to create provider values: factory, service, value, constant and provider. If you want more control over the state, eg state management, you could use one of the other options. More info can be found here.
To dialog or not to dialog
In traditional websites displaying the details in a dialog was a "cheap" trick to keep track of the state in the background. Of course this is still an option with Angular, but there's no need for it. From the UX view, dialogs are "not done" and should be avoided if possible, but it also introduces pains in the areas of responsiveness and printing.
Plunker examples
Some code examples sharing state among controllers/views.
http://plnkr.co/edit/MwJrk5?p=preview
http://plnkr.co/edit/bNJtOP?p=preview

Do we need multiple controllers to implement routes in angularjs?

There is chance that I might not be able to explain my problem properly. Let me try.
I am developing a single page application using angular. This app basically displays the episodes of an online novel series. There is a navigation bar, which has query menus (Like, latest episode, episode of a particular date, episodes with a particular tag, etc). For each of these queries, i want a separate url.
/latest - should display the latest episode
/tag/:tagname - should return all episodes with that tag.
For all these queries, the resultant view is the same (list of episodes). So I will be using the same partial for all routes.
My question is, Should I actually create a new controller for each query? like, LatestEpisodeController, TagController?
Is there anyway I can use the url to determine what the user wants and run that query from within the same controller?
Ofcourse you can use same controller in routing definition, the question is what is the purpose of that? It will be worse to debug it later, if you have a shared functionality it's better to turn it into a factory or service and then use in controllers.
But the answer is YES, you can use same controllers and implement different behaviour basing on i.e. $location.path()
yes you can use single controller for multiple routing..
you can create different functions in controller and in each function do the according job.
In my case I have created different html page for different url and registered same controller for the html pages and in the html page I have called controller method using ng-init in div portion.
You can use same controller and same views as you wish...
$location can help you to get current path or full url if you want and you can call your service depends on your path...
here I write a little example for you to get the idea
PLUNKER

Resources