代码之家  ›  专栏  ›  技术社区  ›  MrPlow

在angularjs中单击按钮时插入/删除模板/视图

  •  1
  • MrPlow  · 技术社区  · 10 年前

    在ASP.NET MVC中编程时,我习惯于使用部分视图进行CRUD操作。现在我正在使用Spring+AngularJS,我希望我能以类似的方式工作。到目前为止,通过使用angular ui路由器,我已经完成了创建/更新的一些基本部分。

    例子:

    布局.html

    <!doctype html>
    <html lang="en" ng-app="Example">
    <head>
        <meta charset="utf-8">
        <title>Test</title> 
    </head>
    <body>
    <div class="container">
        <nav class="row">
            <ul class="nav nav-pills">
                <li ui-sref-active="active"><a ui-sref="clients">Clients</a></li>
            </ul>           
        </nav>    
    </div>
    <div class="container">
        <div class="row">
            <div class="col-md-12" ui-view></div>
        </div>
    </div>
    <script src="libs/jquery/dist/jquery.min.js"></script>
    <script src="libs/angular/angular.min.js"></script>
    <script src="libs/angular-ui-router/release/angular-ui-router.min.js"></script>
    <script src="appjs/app.js"></script>
    <script src="appjs/services.js"></script>
    <script src="appjs/controllers/ClientController.js"></script>
    <script src="appjs/filters.js"></script>
    <script src="appjs/directives.js"></script>
    </body>
    </html>
    

    /客户端/create.html

    <h1>Create new client</h1>
    <form name="clientForm">    
        <div ui-view></div>
    </form>
    

    /客户端/edit.html

    <h1>Edit client</h1>
    <form name="clientForm" ng-show="!loading">
        <input type="hidden" name="id" ng-model="client.id" />  
        <div ui-view></div>
    </form>
    

    /client/createOrEdit.html

    <div class="form-group" ng-class="{'has-error': clientForm.name.$invalid}">
    
        <label for="name">Name:</label>
        <input id="name" 
        name="name" 
        type="text" 
        ng-model="client.name" 
        class="form-control" 
        required />
    
        <span class="help-block" ng-show="clientForm.name.$error.required">Name field is required</span>
    
    </div>
    
    <div class="form-group" ng-class="{'has-error': clientForm.address.$invalid}">
    
        <label for="address">Address:</label>
        <input id="address" 
        name="address" 
        type="text" 
        ng-model="client.address" 
        class="form-control" 
        required />
    
        <span class="help-block" ng-show="clientForm.address.$error.required">Address field is required</span>
    
    </div>
    
    
    <button class="btn btn-primary btn-lg btn-block" 
    ng-click="addOrUpdate(client)" 
    ng-disabled="clientForm.$invalid || clientForm.$pristine">Save</button>
    

    应用程序.js

    App.config(function($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/");
    
        $stateProvider
        /* Client */
        .state("clients", {
            url : "/clients",
            templateUrl : "clients/index",
            controller : ClientListController
        })
        .state("clientCreate", {
            abstract : true,
            url : "/client",
            templateUrl : "clients/create",
            controller : ClientCreateController
        })
        .state("clientCreate.createOrEdit", {
            url : "/create",
            templateUrl : "clients/createOrEdit",
        })
        .state("clientEdit", {
            abstract: true,
            url : "/client/{id:[0-9]{1,9}}",
            templateUrl : "clients/edit",
            controller : ClientEditController
        })
        .state("clientEdit.createOrEdit", {
            url : "/edit",
            templateUrl : "clients/createOrEdit",
        })
    
    });
    

    ClientController.js

    var ClientListController = function($scope, $http) {
        $scope.error = false;
        $scope.loading = false;
    
        $scope.getClientList = function() {
            $scope.loading = true;
            $http.get('clients/clientlist.json')
            .success(function(clientList) {
                $scope.clients = clientList;
                $scope.loading = false;
            })
            .error(function() {
                $scope.error = true;
                $scope.loading = false;
            });
        }
    
        $scope.getClientList();
    };
    
    var ClientCreateController = function($scope, $http, $location) {
        $scope.client = {};
        $scope.loading = false;
    
        $scope.addOrUpdate = function(client) {
            client.id = null;
            $scope.loading = true;
            $http.post('clients/createOrEdit', client)
            .success(function() {
                $scope.loading = false;
                $location.path('/clients').replace(); //redirect to index 
            });
        };
    };
    
    var ClientEditController = function($scope, $stateParams, $http, $location) {
        $scope.client = {};
        $scope.error = false;
        $scope.loading = false;
    
        $scope.getClientById = function(id) {
            $scope.loading = true;
            $http.get('clients/' + id + '/client.json')
            .success(function(client) {
                $scope.client = client;
                $scope.loading = false;
            })
            .error(function() {
                $scope.error = true;
                $scope.loading = false;
            });
        }
    
        $scope.addOrUpdate = function(client) {
            $scope.loading = true;
            $http.post('clients/createOrEdit', client)
            .success(function() {
                $scope.loading = false;
                $location.path('/clients').replace(); //redirect to index
            });
        };
    
        var selectedId = $stateParams.id;
        $scope.getClientById(selectedId);
    }
    

    这是我目前的设置,我对它本身很满意。然而,当试图通过增加一点复杂性来扩展它时,我陷入了困境。

    假设我们的客户可以有多个位置,所以现在每个客户都有一个位置列表。

    我想做的是制作用于创建/编辑位置的部分视图,当编辑或创建客户端时,在客户端创建/编辑页面上显示客户端拥有的每个现有位置的视图、删除它们的能力以及添加新位置的能力。

    在ASP.NET MVC中,我可以使用部分视图、BeginCollectionItem和一些jQuery来实现这一点。我应该如何用角度来处理这个问题?

    我尝试使用ng repeat和ng include,但是当尝试添加/删除位置时,没有任何内容反映到ng repeat,而且我也不喜欢这种方法。

    我认为点击按钮后没有发生任何事情的原因与我收到 Async XHR deprecated warning 使用insertLocation方法单击按钮时,在控制台中。

    insertLocation() 看起来像这样

    $scope.insertLocation = function() {
        $scope.client.locations.push({});
    }
    

    并放置在create和edit控制器中,并且客户端var也被编辑为如下所示

    $scope.client = {locations: []};

    请注意。我并不是在寻找解决这种情况的方法(虽然这会有所帮助),而是更多的关于我的方法的建议。这是错的吗?如果是这样,正确的心态、正确的方法是什么?

    2 回复  |  直到 10 年前
        1
  •  4
  •   Community T.Woody    7 年前

    这个 n 可以使用 ng-repeat 具有用于添加新位置的额外表单组:

    <div class="form-group" ng-repeat="location in client.locations">
        <label for="address">Address:</label>
        <input type="text" model="location.address"  />
        <a ng-click="remove(location)">remove</a>
    </div>
    
    <div class="form-group">
        <label for="address">Address:</label>
        <input type="text" model="newlocation.address"  />
        <a ng-click="addLocation()">add</a>
    </div>
    

    控制器看起来像这样:

    .controller('MyCtrl', function($scope, client) {
    
        $scope.client = client;
        $scope.newlocaiton = {
            address: null
        }
    
        $scope.remove = function(location) {
            // using underscore.js/lodash.js for remove
            _.remove($scope.client.locations, location);
        };
    
        $scope.addLocation = function() {
            // ignoring whatever you might need to do calling 
            // server to persist etc. Just adding to client
            $scope.client.locations.push($scope.newlocation);
        };
    })
    

    至于“部分”,我并不完全清楚您想要什么,但Angular标记重用的方式是通过如下指令:

    .directive('LocationForm', function() {
        return {
            restrict: 'EA',
            scope: {
                location: '=',
                onRemove: '='
            },
            templateUrl: 'location.edit.html',
            link: function(scope, el, attr) {
                // omitted
            }
        }
    })
    

    location.edit.html

    <label for="address">Address:</label>
    <input type="text" model="location.address"  />
    <a ng-click="remove(location)">remove</a>
    

    和用法:

    <div class="form-group" ng-repeat="location in client.locations">
        <location-form location="location" />
    </div>
    

    (注意,我没有这样做,所以指令示例可能不完整)

    参见:

        2
  •  2
  •   MrPlow    10 年前

    为了完整起见,以下是我的解决方案: Plunker link .

    为了使事情更简单,我将客户机位置之间的多对一关系替换为一个项及其子项之间的多到一关系。

    因此,按照完成顺序:

    1. 我已经创建了一个子项输入的“部分”html(可以说是一个“可重用”模板)。它看起来像这样: _SubItem.html (我决定重用ASP.NET MVC方式,在部分前面加下划线)

      <div class="form-group">
        <label for="subinput1">subinput1</label>
        <input type="text" id="subinput1" ng-model="subitem.subinput1" class="form-control">
      </div>
      <div class="form-group">
        <label for="subinput2">subinput2</label>
        <input type="text" id="subinput2" ng-model="subitem.subinput2" class="form-control">
      </div>
      <div class="form-group">
        <label for="subinput3">subinput3</label>
        <input type="text" id="subinput3" ng-model="subitem.subinput3" class="form-control">
      </div>
      <button class="btn btn-danger btn-block" ng-click="removeSubItemAt($index)">Remove SubItem</button>
      
    2. 然后我用它创建了一个指令。目前我对这个指令很不满意,因为它没有像上面craigb的答案那样使用一个独立的作用域。它不使用隔离作用域的原因是因为我需要引用ng repeat的$index,最重要的是引用所属项控制器的控制器作用域,以便我可以使用 removeSubItemAt(index) 方法就我而言,这本身就是一个糟糕的设计。理想情况下,我希望创建一个链接到指令本身的特殊控制器,并让它引用子项所有者,以便指令控制器拥有必要的方法来处理所有者中自己的集合。或者只传递索引和删除函数。然而,我目前还没有足够的知识来完成这样的任务。以下是指令目前的样子:

      .directive('subItemPartial', function(){
          return {
            restrict: "E",
            templateUrl: "_SubItem.html"
          };
      });
      

      看起来很简单。下面是它在 index.html

      <div class="col-xs-4" ng-repeat="subitem in item.subitems track by $index">
        <sub-item-partial></sub-item-partial>
      </div>
      

    这基本上就是部分指令。项控制器包含用于创建和删除子项的方法。此外,您可能会注意到ng repeat是 track 预计起飞时间 by $index 。原因是我希望能够一次创建n个子项,填充它们并将它们传递给服务器。自从 ng-repeat 默认情况下使用对象本身而不是其索引,它不允许重复条目。