UNPKG

knowhow-server

Version:

A personal workflow engine that can manage and use any network connected host

137 lines (127 loc) 5.89 kB
<a href="http://github.com/angular/angular.js/edit/master/docs/content/cookbook/mvc.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code> <div><span class="hint"></span> </div> </h1> <div><div class="cookbook-page cookbook-mvc-page"><p>MVC allows for a clean and testable separation between the behavior (controller) and the view (HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the view. This makes it very easy for the controller and the view to share the model.</p> <p>The model is a set of objects and primitives that are referenced from the Scope ($scope) object. This makes it very easy to test the controller in isolation since one can simply instantiate the controller and test without a view, because there is no connection between the controller and the view.</p> <h3 id="source">Source</h3> <div source-edit="" source-edit-deps="angular.js script.js" source-edit-html="index.html-198" source-edit-css="" source-edit-js="script.js-197" source-edit-json="" source-edit-unit="" source-edit-scenario="scenario.js-199" source-edit-protractor=""></div> <div class="tabbable"><div class="tab-pane" title="index.html"> <pre class="prettyprint linenums" ng-set-text="index.html-198" ng-html-wrap=" angular.js script.js"></pre> <script type="text/ng-template" id="index.html-198"> <h4 id="source_tic-tac-toe">Tic-Tac-Toe</h4> <div ng-controller="TicTacToeCntl"> Next Player: {{nextMove}} <div class="winner" ng-show="winner">Player {{winner}} has won!</div> <table class="board"> <tr ng-repeat="row in board track by $index" style="height:15px;"> <td ng-repeat="cell in row track by $index" ng-style="cellStyle" ng-click="dropPiece($parent.$index, $index)">{{cell}}</td> </tr> </table> <button ng-click="reset()">reset board</button> </div> </script> </div> <div class="tab-pane" title="script.js"> <pre class="prettyprint linenums" ng-set-text="script.js-197"></pre> <script type="text/ng-template" id="script.js-197"> function TicTacToeCntl($scope, $location) { $scope.cellStyle= { 'height': '20px', 'width': '20px', 'border': '1px solid black', 'text-align': 'center', 'vertical-align': 'middle', 'cursor': 'pointer' }; $scope.reset = function() { $scope.board = [ ['', '', ''], ['', '', ''], ['', '', ''] ]; $scope.nextMove = 'X'; $scope.winner = ''; setUrl(); }; $scope.dropPiece = function(row, col) { if (!$scope.winner && !$scope.board[row][col]) { $scope.board[row][col] = $scope.nextMove; $scope.nextMove = $scope.nextMove == 'X' ? 'O' : 'X'; setUrl(); } }; $scope.reset(); $scope.$watch(function() { return $location.search().board;}, readUrl); function setUrl() { var rows = []; angular.forEach($scope.board, function(row) { rows.push(row.join(',')); }); $location.search({board: rows.join(';') + '/' + $scope.nextMove}); } function grade() { var b = $scope.board; $scope.winner = row(0) || row(1) || row(2) || col(0) || col(1) || col(2) || diagonal(-1) || diagonal(1); function row(row) { return same(b[row][0], b[row][1], b[row][2]);} function col(col) { return same(b[0][col], b[1][col], b[2][col]);} function diagonal(i) { return same(b[0][1-i], b[1][1], b[2][1+i]);} function same(a, b, c) { return (a==b && b==c) ? a : '';}; } function readUrl(value) { if (value) { value = value.split('/'); $scope.nextMove = value[1]; angular.forEach(value[0].split(';'), function(row, col){ $scope.board[col] = row.split(','); }); grade(); } } } </script> </div> <div class="tab-pane" title="ngScenario e2e test"> <pre class="prettyprint linenums" ng-set-text="scenario.js-199"></pre> <script type="text/ng-template" id="scenario.js-199"> it('should play a game', function() { piece(1, 1); expect(binding('nextMove')).toEqual('O'); piece(3, 1); expect(binding('nextMove')).toEqual('X'); piece(1, 2); piece(3, 2); piece(1, 3); expect(element('.winner').text()).toEqual('Player X has won!'); }); function piece(row, col) { element('.board tr:nth-child('+row+') td:nth-child('+col+')').click(); } </script> </div> </div><h3 id="demo">Demo</h3> <div class="well doc-example-live animate-container" ng-embed-app="" ng-set-html="index.html-198" ng-eval-javascript="script.js-197"></div> <h2 id="things-to-notice">Things to notice</h2> <ul> <li>The controller is defined in JavaScript and has no reference to the rendering logic.</li> <li>The controller is instantiated by Angular and injected into the view.</li> <li>The controller can be instantiated in isolation (without a view) and the code will still execute. This makes it very testable.</li> <li>The HTML view is a projection of the model. In the above example, the model is stored in the board variable.</li> <li>All of the controller&#39;s properties (such as board and nextMove) are available to the view.</li> <li>Changing the model changes the view.</li> <li>The view can call any controller function.</li> <li>In this example, the <code>setUrl()</code> and <code>readUrl()</code> functions copy the game state to/from the URL&#39;s hash so the browser&#39;s back button will undo game steps. See deep-linking. This example calls <a href="api/ng.$rootScope.Scope#methods_$watch"><code>$watch()</code></a> to set up a listener that invokes <code>readUrl()</code> when needed.</li> </ul> </div></div>