Angular JS , $watch and web performance - angularjs

I want to ask one question, suppose my web page is like a text editor, I have some boxes where user can write.
Suppose i want to implement autosave in angular . I have some ng-models for the info inside those boxes, and now i use ng-watch to listen to all of my boxes models.
So ,In a normal user mode ng-watch is continuously getting that my models are changing.
Will this method produce low performance in my web app?
If it did,Would you recommend me a way to implement an autosave on angular.
-----------EDIT---------
in brief : what i want to know is, if used $watch for multiples scopes who are continuously changing can affect to the web page performance

Maybe you can only bind the text to the model via ng-model and make a timer with some interval you want. That timer would then post the status to the backend.
About the performance, ng-watch will, as you said fire very often. You'll probably want traffic to the backend every keystroke.
Hope it helps! Ask for more info if you want :)
EDIT:
If you want live updates, you should look at something like socket.io.
EDIT 2:
I would not either fear for the performance, but for simplicity. I've used ng-watch a few times, and everything becomes harder to debug.
Cheers!

Well, instead of $watch'ing the models, you may opt for "ng-change" OR ng-blur instead.
If you use ng-change, then you may also set a timer, that will only re-evaluate your model once user stops typing for a second.
ng-blur triggers only once, after user is done typing and blurs/unfocuses the input.
Note: If you dont want to send autosave requests to the backend too often, you may autosave in client side ( using localStorage ), which would be instant. Then, you can send that final saved info to your sever once user is done with editing and submits a form/is ready to continue.

Related

How does React store and react to changing state exactly?

I am scraping a website that uses React for the front-end. So far it seems that I have to use their search form in order to arrive at the results page.
The problem is that the site clears out the search form's selected options from a dropdown (its state) every time the page is refreshed and therefore it makes scraping significantly slower. I know that it's working as intended, but if there was a way I could directly manipulate the state then it could speed up my scraper as opposed to re-selecting all the choices from the little buttons.
I don't think it uses any type of persistent storage or local storage at all, for every selection, otherwise the form probably wouldn't be cleared on refresh.
I can see that the years options for the form are always present in a data-attribute (data-years=["2017", "2016", ...]) but only for the years. And when a year (or any option from the dropdowns) is selected, a hidden field is populated with a value such as <input type="hidden" name="year" value="2017">.
Is this all that React uses for temporary storage (aka. state)—hidden fields?
And for the second part of my question, what type of event is fired off when there is a state change? How could I trigger it manually? When I select a year, for example, I want the form to give me the options for the next dropdown—given the year.
React does not use the DOM at all to maintain state. The example you provided is simply a poorly written React app. Normally everything will kept in memory (closured code so nothing in window/global) and React will update the DOM as she wants. :)
This means I don't think you'll be able to read/detect React instrinsic state changes from the outside. Interactive scraping should work like a user using the page, without any hint of what tech it's really using.
Depending on the technology you're using for scraping, you could indeed simulate or generate the real DOM events. When we need to write some end to end tests for a React app using the ubiquitous Selenium server, we normally have to manually click on buttons, options and so on and allow time for the React app to react accordingly and do its magic (like fetching more data and updating the page) and afterwards read document contents to verify everything was working. It's basically "scraping" with a desired output to verify, your test assertions.
If you're scraping static pages only (curl style: fetch the HTML and work your way with the original HTML response), I don't think you'll be able to handle a Javascript form. You need your scraper to be interactive.
Something like PhantomJS apart from the mentioned Selenium/WebDriver may help.

Model overwrites data in input fields when polling or pushing data from API

When polling a model (object) or pushing a model from a RESTful API to AngularJS via xSockets the data in input-fields is overwritten.
Let's say I edit the first name of a user and while I edit the user xSockets or the timed polling using the $interval to refresh the model, is writing over the changes I have made to the first name before I had a chance to save.
How can I push or poll a model into the view without overwriting the input-field as I am editing?
Your information is a bit limited, but assuming that I understand the question correctly, you have two options.
You can disable realtime data refreshing on the edit page (I wouldn't let my app continuously refresh data where I am supposed to be providing input anyway).
You could add a change listener on your inputs that tells xSockets to not refresh the data on that field again until you have submitted the form.
Again, I'm not entirely sure what your situation is without seeing any code, but hopefully this helps.

Using 2 views and sharing data in AngularJS

Im trying to share data between 2 views. I need to use the 2 views at the same time on two different machines. One is controlling the other(ex: a counter) 1st view has next(+1) and the other just displays the result. I want the data to synchronized/binded. I do not want to have to refresh the 2nd page or to have to pull data with a timer or otherwise.
My idea was to use ng-view and routeProvider, I know that when the view changes the scope is cleared so I tried to use a parent controller/scope, the data is shared but I have to refresh the page on my 2nd view. I tried a service, same thing. I tried to $watch the result of the service but on the second controller/view no event is picked up so the view doesn't update.
what is the way to go? I was thinking about broadcasting or emit a custom event and trying to catch it, will that work? Am I just not binding to the service correctly? Would ui-router work better? I feel there should be an easy way to do this.... Im not seeing it! Please help if you can.
One of the simplest (in my opinion) implementations of client-client communication is using WebSockets. While that does have compatibility limitations (some browsers), that can easily be overcome by using a library like socket.io. Also, it's easy to write an Angular wrapper/service over socket.io that can be shared across components of your app, or even different modules.
It's also pretty simple to write a Node backend with socket.io
This might be a good read.
I would suggest you to focus on pushing stream rather than sharing it. Some how you need to push stream to second view which is changes in first view.
You may want to check this
Is there some way to PUSH data from web server to browser?

Maintaining application state across single page view flips and multi-page flips

Well, as technology progresses, issues we solved long ago crop up again.
Back in the dark ages, when PHP and ASP were considered awesome, we always had a problem with view states. If you had a page with say a dozen select combo boxes on it, your user chooses some combination and hits next, then realizes they screwed up and hit the back button on the browser, the combo boxes would be back in the default state, usually with option[0] selected. In order to prevent this, we had to write boatloads of boilerplate code that would save the state of those combo boxes to a cookie, or session variable, or something so that when the user hits the back button, we can reload the combo boxes back to the state they were in when they left.
This problem was compounded even further if you had a datagrid on the screen. Because then you would have to come up with some slick way of saving that grid somewhere to prevent from having to hit the database again.
Then came the light. Browser developers realized that most web developers were on the verge of going back to writing terminal programs in Cobol due to this issue and added UI caching to the browsers. This allowed us webdevs to not have to worry about this anymore except in odd situations.
So, life was good. Then someone came up with the bright idea of trying to replicate GWT without all the hassle and the web explodes with all these javascript frameworks. The one im dealing with specifically at the moment is AngularJS 1.2.10 with Angular-UI. I have until Friday (most likely wednesday tho) to make an initial assessment on if this technology is a viable alternative to our current standard (thats pretty much universally hated) JSF.
So, i follow some guides, pound my head against the desk a few times, and I have an angular app with 3 actual HTML pages, each HTML page with 2 views.
Before you go there, understand we can't use it unless we can do multi-page JS apps. Some of the applications that this will be worked into have been in development for a decade or more and its simply not financially practical to scrap an the entire UI and start over again. We would instead be doing things like taking these 50 struts pages and converting them to angular/rest and linking them seamlessly back into the remaining 800 struts pages of the application.
So in my exercise of playing with this, I encounter my old nemesis. Back button view state issues.
I have been playing with the UI-route system. The fact that I can deep link using the route system solves part of my problems. But, if say I have a search page like this:
view-search
combo: search type [member,nonmember]
combo: result type [detail,summary]
combo: search state {all the states]
textbox: contract number
etc etc etc
And various combinations of combo box selections and text entries comes up with a list of 1000 people. Now the user selects one of those people on the data grid and it takes you to view-detail. Well the fact that you can use routing to do something like index.html#detail/bob is cool, but if the user realizes thats the wrong bob and hits the back button, they get a blank search screen again and they have to enter everything over and worse yet, send another search to the database to rebuild the datagrid. Some of these screens have 50 or more options to choose from when searching for data so trying to put all of them into the URL routing sounds completely impractical to me.
Now in my research I found this post:
Preserve state with Angular UI-Router
And that has promise mainly because I have a view state object that I can store into a Redis database or a session EJB for cases when the user actually jumps out of angular and into the legacy Struts application, then back buttons back into the angular application, but the fact still remains that on some of these pages, that is a huge amount of boilerplate code that we would have to write in order to make it work.
I don't really mind the idea of having to manually save off the view state object and read it back in from a Redis server or something anytime a user enters or leaves an HTML page in the system. What i'm really looking for is a way to automatically generate the object that is to be saved without having to write volumes of boiler code.
Is this possible? I keep reading the ui-route documentation but it doesn't look like this is addressed, at least not that i've translated yet.
If this is possible, what controls should I be looking at?
thanks
-------------- Edit
I just thought of something. There is one central scope to each of the single page applications. (Im basically going to be building a multiple single page apps and hooking them together) So if i use a naming convention, something like this
$scope.viewstate.view-search.searchType
$scope.viewstate.view-search.resultType
$scope.viewstate.view-search.searchState
Then the viewstate object should simply be a js array and when I create a function to move to struts.do, i can simply save that array off to the Redis server as a nested map object. Then when my user back buttons back into the angular app, i can capture that using the route system and retrieve that viewstate object from Redis and insert it back into my scope, thereby rebuilding the scope for the entire single page app in one shot.
Would that work?
I believe that you have a very complicated issue of trying to keep the view states between your varying pages with the amount of data in your pages. I think that the only real effective way to do this is to write an angular service that you can then pass to your various pages. as You already know the service is a singleton that you can use in various controllers and could be utilized to maintain the view state as you described. here take a look that this link and see if it will help: http://txt.fliglio.com/2013/05/angularjs-state-management-with-ui-router/
After some thought what you suggest in your edit might work, but I would still use a service to retrieve that array of data, as it would make it easier to reinsert in to angular scope
I am exploring something similar for an Angular app that I am writing. Keeping a user login during a page refresh is easy. Displaying the state on the page after a refresh is an entirely different problem.
How long must the state be persisted? I'm evaluating two possibilities.
First, saving the state (current form values or whatever) to the database. As the page changes, incrementally save the state to the database. On a browser refresh check the database for saved values.
Second is to use local browser storage. This is 5 megs of storage. 5 megs is a lot of text. Again this data would incrementally be saved into storage. When the browser refreshed, simply load data from localStorage.

Angular ui-router nested views don't refresh data retrieved by Angular Services

I have a nontrivial Angular SPA that uses ui-router to manage multiple views, many of which are visible at the same time. I need models to be visible across controllers, so I have services written that allow me to have controllers pull down fresh copies of model data that has been updated.
I apologize in advance for the length of the question, but I will state the problem then state what I have done to address issues I'm sure others in the Angular community have struggled with.
I believe my problem is not understanding the lifecycle of controllers / views, because I get behavior where a controller initializes correctly the first time I go there, but then seems to never run again, even when I navigate to it using something like $state.go("state name").
In one view (contrived example), I show a summary of information about a customer, and in another view I allow a user to update that customer's more detailed profile. I want a user to edit, say, the customer last name in the detailed view, and have the summary view automatically recognize the change and display it.
I have a fiddle that shows 3 views and a simple password changing Service. The flow goes like this:
You can see each view gets initialized and displays the initial password retrieved from the service. All views are in sync with the DataService.
The middle view allows you to enter a new password and change the one stored in the service. Console logging confirms that the service picks up the new password just like you would expect.
(odd behavior #1) When the DataService receives the new password, I would expect the other 2 views (top and bottom) to display the new one. They don't... they still display the initial password.
There is a button to allow a user to go to another state via $state.go("state name") (a child state of the original) which also retrieves the password and displays it. This works the first time (see #5). Now the top view shows the outdated password, the middle view shows the new one, and the bottom one shows the new one as well. This seems normal, since the new view is invoked after the DataService contains a new password value.
(odd behavior #2) If I click back in the middle view and change the password again, and click the button to change states again, the bottom view (which updated just fine in step #4) no longer updates its copy of the password. Now all 3 views show different passwords, even though I am using a single service to pass values between controllers as suggested pretty much everywhere you look for Angular best practices.
Some possible solutions:
Tim Kindberg has an excellent slideshow here that seems to recommend using ui-router's state heirarchy to "pass" data among views that need to pick up values from other views. For a smaller-scale app I think I would settle on this, but I expect our application to have 30+ views displaying data from over 100 REST endpoints. I don't feel comfortable maintaining an application where all the data is being shared by a complex inheiritance tree. Especially using a routing framework that is at version 0.2.8.
I can use events to have controllers listen for changes in the data model. This actually works well. To accommodate performance concerns, I am using $rootScope.emit() and a $scope.$onRootScope('event name') decorator I found on here. With this approach I am less concerned about event performance than I am about wiring this huge app with a bunch of event listeners tying everything together. There is a question about the wisdom of wiring a large app using angular events here.
Using $watch on the value in the DataService? I have not tried this but I am hesitant to hinge an app this size on hundreds of $watches for performances reasons.
A third-party library like bacon.js (or any of a dozen others) that may simplify the event spaghetti, or create observable models that my controllers can watch without the risk of $digestageddon. Of course, if there is a concise way to handle my issue using Angular, I'd prefer not to muddy the app with 3rd party dependencies.
Something that lets controllers actually reference .service modules by reference, so I don't have to depend on tons of event wiring, complex state hierarchies, 3rd party libraries, or seeding the app with hundreds of $watches and then kicking off $digests to update controllers' references to Angular services?
Some solution that relies on time-tested OO and design patterns and not a 3rd-party library or framework that has a version that starts with 0.*.
Thanks in advance... I appreciate the help!
This is no problem of ui.router. If you intend for your model (your data service) to be a single source of truth, you have to refrain from destroying it.. err.. the reference to it that is. And in your case, assigning a primitve (a string) directly to the scope, instead of a reference to it. In other words...
var password = {pw:'initial value'};
and then later setting/binding only on
password.pw = newpassword
{{password.pw}}
Heres a fiddle. And also here is a short little read on scopes, It also includes a video of an angular meetup where Misko talks about "always have(ing) a dot in your model" link and how the $scope is a place to expose your model, not be your model. (aka not a place to assign primitives like password = 'initial value')
Hope this helps!
try remove the animation property of your ion nav view.
remove the property
animation="slide-left-right"
it would be ok.

Resources