Nested scopes in AngularJS without nested DOM elements? Creating a view/activity "stack" -
i'm developing simple crud application view end edit generic objects/rows in database. each type of crud-related action (browse, view, create, edit, delete, search...) has corresponding type of view. instances of view "browse table a" or "edit row 45 of table b".
views have actions can create child view, example user may browsing table , click "edit" on particular row. makes views stack, topmost view displayed user. view pushed onto stack when new action triggered, , popped when action completes or user cancels.
right code looks this:
app.js:
angular.module('myapp', []) .controller('appcontroller', function($scope) { var viewstack = []; $scope.currentview = function() { return viewstack[viewstack.length-1]; }; $scope.pushview = function(view) { viewstack.push(view); }; $scope.popview= function() { viewstack.pop(); }; $scope.pushbrowseview = function(table) { var view = { type: "browse", table: table, rows: [], refresh: function() { // load data view.rows via ajax }, // ... }; view.refresh(); $scope.pushview(view); }; $scope.pushcreateview = function(table) { var view = { type: "create", table: table, newrow: {}, // ... }; $scope.pushview(view); }; $scope.pusheditview = function(table, row) { var view = { type: "edit", table: table, row: row, // ... }; $scope.pushview(view); }; // more view types... }) .controller('browsecontroller', function($scope) { $scope.create = function() { $scope.pushcreateview($scope.currentview().table); }; $scope.edit = function(row) { $scope.pusheditview($scope.currentview().table, row); }; }) .controller('createcontroller', function($scope) { $scope.submit = function() { if(newrow.isvalid()) { // post server window.alert('row submitted'); $scope.popview(); } else { window.alert('not valid'); }; }) .controller('editcontroller', function($scope) { // similar createcontroller... }) // more controllers other view types
page.html:
<body ng-app="myapp" ng-controller="appcontroller"> <!-- stuff --> <button ng-click="popview()">back</button> <!-- more stuff --> <div id="theview" ng-switch="currentview().type"> <div ng-switch-when="browse" ng-controller="browsecontroller"> <button ng-click="create()">new row</button> <table> <!-- header goes here --> <tr ng-repeat="row in currentview().rows"> <td><button ng-click="edit(row)">edit</button></td> <td ng-repeat="column in currentview().table.columns"> {{ row[column] }} </td> </tr> </table> </div> <div ng-switch-when="create" ng-controller="createcontroller"> <form> <div ng-repeat="column in currentview().table.columns"> <label>{{ column }}</label> <input name="{{ column }}" ng-model="currentview().newrow[column]"> </div> </form> <button ng-click="submit()">submit</button> </div> <div ng-switch-when="edit" ng-controller="editcontroller"> <!-- kinda "create" --> </div> <!-- , rest of view types --> </div> </body>
it's lot fancier that that's gist of it. problem there 1 root scope app, 1 child scope each type of view. since there more 1 instance of each type of view on stack @ once, state of each view needs stored in object in viewstack
instead of in view type's $scope
.
this doesn't @ seem proper way of doing things. make sense there 1 scope per view instance, each 1 being child of scope of view beneath on stack. way have events naturally broadcast top view through others. wouldn't have prefix every state variable currentview()
. way can think of doing recursive directive potentially creates deeply-nested dom elements don't want.
this seems pretty common design pattern. there better way of doing it?
going describing, think each of views better suited directive
isolated scope
instead of putting each view viewstack
object on common scope.
in example code getting table information appcontroller
, storing them on $scope views use. can't see how views getting scope, assuming coming web service where, move storage , fetching of data directive itself. eg,
app.directive('exampleview', ['myviewservice`, function(myviewservice) { return { restrict: 'e', scope: { 'mytable': '=', 'myrows' : '=', 'onpopview': '&' }, templateurl: 'url/to/specific/view/template.html', link: function($scope,element, attributes) { //logic processing values , saving server/whatever required $scope.submit = function() { if(newrow.isvalid()) { // post server window.alert('row submitted'); } else { window.alert('not valid'); } }; if($scope.onpopview) { // tell parent controller view discarded? $scope.onpopview(); } } }; }]);
the onpopview
might not appropriate doing, used example creating event/callback parent controller hook into. allows separate responsibilities between directive , parent controller(s).
Comments
Post a Comment