Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Separating Model and View State in AngularJS

I've got a big complicated SPA that I'm coding in angular. In it, I need to keep track of actual Model data - operationalized as "stuff that I get from and send to the backend API server". I also have viewstate data - "stuff I keep track of, but don't send to the API server". Model data is stuff like user nicknames or forum post bodies, whereas viewstate data is "this particular UI element is expanded" - it's application state basically.

What I'm wondering is: is there a best-practices approach to this? In my more complicated controllers, I've got an ng-repeat of elements, each element has expando-UI elements. The temptation is to put those expandos inside an ng-if and attach a .showing variable to the object. For example one could imagine this kind of text: ng-repeat="user in users", ng-click="user.showing = !user.showing", ng-if="user.showing" in a few divs. This is really handy because all the information we need about the view state of a repeated item is right there on the repeat.

This also smells terrible - it potentially overwrites fields that were fetched from the API server, and since I cache data models to save on API roundtrips (and handle realtime updates), it also means that view state gets preserved when the user navigates away and then back to the same place in the SPA, or that the view state would be linked in the event the same data is displayed twice on the screen (say, the same profile is showing in three places on the screen as three replies to a post).

I've got some ideas about what to do here. I could encapsulate all the view state variables in their own place in the controller, which has the side-effect of making ng-repeats a lot harder to pull off (you have to look up the view state variable using the $index property probably).

I could encapsulate this one problem in a directive, calling ng-repeat on the directive, which would itself have isolate scope and only has one set of state variables to track (so it therefore doesn't need to worry about tracking complex view state).

I could do something else entirely that the SO community suggests.

I'm leaning toward the directive route. This seems like the Angular Way of doing things. Each UI element doesn't really need to share its state outside of itself, I am currently only really doing this because my initial web mockups were big HTML templates that I got and then attached ng-repeat directives to. I can break the Post, Comment, Author, and so on elements into directives, then they just keep their state on their own.

like image 208
pfooti Avatar asked Feb 04 '26 02:02

pfooti


1 Answers

Yeah, for what it's worth, I ended up breaking everything into directives. Basically, any item inside an ng-repeat that needs to track view state gets its own directive (and therefore its own isolate scope). I also got into the habit of stashing view-related variables on scope.view, so scope.view.showingExpandedReply = true, or whatever. That way I didn't have to pollute the data model with view state information.

like image 157
pfooti Avatar answered Feb 05 '26 20:02

pfooti