How to avoid ng-repeat repopulate unaffected data - angularjs

What's a good way to solve this?
I have a list of items on user's view. Each item could be expaned - only one at a time. (I'm using Angular Bootstrap Accordion). In the expanded container I have a password input. The problem is that I'm updating the item list every 20 secs, and the list might be repopulated exactly when the user is entering the password, and everything gets totally messed up.
*Imagine this like a list of WiFi Networks - with continuous scanning.

The problem is, when you rfresh list's model it is detected by directive's (accordion?) watcher which launch a compile, e.g. DOM rbuild of component, so there could be some ways to avoid loss of user's process:
right way (imho) is to move form out of the component whose model refreshes in such way
try to prevent refreshing while user interacts with form
deregister interval/timeout you use to refresh when form(or any of it's fields focused), and set interval back on submit/cancel/blur
try build 'shadow' model and refresh it every 20 seconds, then set watcher to it manually (in this case you will get a watcher deregister function to turn off watcher) and in this watcer refresh model, to which your accordion is linked, so again onfocus you will be able to deregister watcher.

Related

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

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.

Structuring an angular app for server side filtering and pagination

tl;dr
What would be best approach for structuring an angular app which supports filtering and sorting on the server side using radio button filters on client side
Context of the app:
I have a sample movie list app, where movies have genre and style to categorize them. They can be sorted based on name, rating, year of release. The backend is very clear, I pass the filters to url in the form of query parameters and data is returned and pagination is also addressed. From the client side I create the url and attach the string params to it. However I have tried few implementations of filters and sorting on the client side and wasnt satisfied. every implementation involves using radio buttons for filters. The following approaches were used by me.
Approaches used:
Create few filters based on genres and styles of movies, launch an event when one radio button is clicked, pass the filter-radio model in the event. Listen for the event in a movieListDirective and then create the url followed by triggering the server call.
Create filters and pass the data in a service, launch an event whenever a radio button is clicked. Listen for the event and receive the data from the service. Create the url and initiate the server call.
Not yet used this approach but thinking of giving it a try
On click of radio button push the data in the browser url in form of query parameters. Listen for url change event inside the directive and trigger the server call
I'm also thinking of using UI router. Create an abstract state for filter and sort button. Put the movieListDirective inside the child state.
I'm just not satisfied with my 2 approaches and think that there's a huge room for improvement. Can anyone please suggest a very scalable approach or something to improve the existing approach which I'm using. Thanks in advance.
**I'm using IONIC. I would like to take advantage of the pull to refresh and infinite scroll features. These have to be put inside the ionic-content directive. Hence the approach used should satisfy this requirement **
Well, if I were you I would change a variable in my $scope and listen its changes to request again with your filters.
I made a Plunker to help you.
https://embed.plnkr.co/cNZ1Um7FycaPBjef5LI1/
In this Plunker, I added the ng-model to my radio buttons. When these radio buttons are selected, they change my variable with their values.
<input type="radio" value="new" ng-model="area">
This radio button above change $scope.area value to "new". Then, my controller listen to this change event and call my $scope.requestAPI function.
$scope.$watch('area', function() {
$scope.requestAPI($scope.area, $scope.category);
});
This function use the values of $scope.area and $scope.category to make a request. Changing their values, you change the request.
It is exactly the feature that you need.

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

Display n time ago on various items using jquery, [issue with new elements generated after the loading the DOM]

I am using Jquery plugin http://timeago.yarp.com/ for showing time.
Issue is timeago will not take effect for dynamically generated items.
$(document).ready(function() {
$(".timeago").timeago(); // works perfectly fine for the items which are loaded on page load
//$(".timeago").live(timeago()); // gives me an error ie timeago is not defined
//$(".timeago").live($(".timeago").timeago()); // gives me an error too much recursion.
jQuery.timeago.settings.allowFuture = true;
});
From some google search I got to know something ie:
Using live is the same as using bind, except that it is limited only to the events click, dblclick, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, and mouseup.
Now how can do it cause I dont have any click event? How can I bind this?
.live() and .bind() assign callbacks to event. In your case, you don't have an event to assign the function to and so it fails.
You can, in theory, assign your callback to a custom event. You will however have to manually trigger the event (using .trigger()) whenever your item is generated. For example:
$("abbr.timeago").live("timeago", function() {
$(this).timeago();
});
// ... and in the bit that generates your item
$new_item.trigger("timeago")
Demo: http://jsfiddle.net/ZjuW4/9
Of course, using .live() in this situation is purely academic and does not really serve a good purpose.
If you do have access to the code that's generating the items, you can simply chain in the call to .timeago() as the items are generated, i.e. http://jsfiddle.net/ZjuW4/3/
take a look in this topic
here was discussed how to put timeago on dynamically loaded items
for example the results of an ajax request.
Activate timeago on newly added elements only
PS: allowFuture does not have anything to do with putting timeago on newly created items on your page. it just allows dates in the future (f.e. "in 3 days", "next week")

Resources