在Angular.js中处理AJAX驱动的DOM更改的正确方法是什么?

时间:2014-08-15 17:33:39

标签: angularjs angularjs-directive angularjs-scope

我意识到"正确的方式"是主观的,但我认为这是一个特定的问题,有一种最佳实践方法。

我是Angular的新手,并试图了解以下规定的机制。

我有一系列依赖<SELECT>,它们在发布时没有与之相关的任何数据。

第一个项目通过<option>获取一些项目(需要填充为$http),生成的JSON响应用于填充下一个<SELECT>

根据回复,可能会或可能不会有后续的<SELECT> s,这意味着如果用户选择了选项1,则会有后续选择,但是如果他们选择选项2,那么就没有&#t; t 39;我希望将所有可能的<SELECT>硬编码到我的模型中,我需要它具有弹性。

所以...从我正在阅读的内容来看,controller不适合处理这个问题,我应该使用directive,尽管我有很难找到关于如何根据需要准确地处理修改DOM的具体细节来引入新<SELECT>的文档。另外,我不清楚我应该在哪里进行AJAX调用,以及如何将它们连接到通过修改UI来响应的任何内容。

我希望有人可以指点我一些有关如何处理此(或类似)方案的有效教程。

2 个答案:

答案 0 :(得分:2)

你是完全正确的,你需要使用一个指令来进行DOM操作,但在这种情况下我不认为你必须自己编写任何一个,你可以使用angular提供的内置指令

您还应该坚持通过服务提供数据(在这种情况下,option值等)的最佳做法。我假设你可以自己处理服务方面的问题。因为我很懒,所以我只需要手动将数据输入到我的控制器的范围内(您仍然需要一个最小的控制器来将数据从服务中获取到范围内)。

  

第一个项目通过<option>获取一些项目(需要填充为$http),生成的JSON响应用于填充下一个<SELECT>

目前尚不清楚你是否已经研究过如何做到这一点,但你会想要使用ng-options指令:

如果你有这样的数据:

[
  { key: "Ford fiesta", value: "fordFiesta" }, 
  { key: "Audi TT", value: "audiTT" }
]

您可以使用以下内容 标记:

<select ng-model="selection" 
        ng-options="options.label as (options.key, options.value) in options">

同样,我很懒,所以我后来使用了一个更简单的标记,其中键与值相同。

  

根据响应,可能会或可能不会有后续<SELECT> s,这意味着如果用户选择选项1,则会有后续选择,但如果他们选择选项2则没有,我不希望要将所有可能的<SELECT>硬编码到我的模型中,我需要它具有弹性。

为此,您需要一个比简单的选项数组更复杂的数据结构。在我的例子中,我设计了如下内容:

[ 
  {
    modelName: "apples"
    title: "Do you like apples?"
    options: [ "yes", "no" ]
    followUps: [
      {
        modelName: "appleType"
        condition: "yes"
        title: "Do you prefer Granny smiths or snow white?"
        options: ["Granny Smith", "Snow White"]
      }
    ]
  },
  {
    modelName: "pears"
    title: "Do you like pears?"
    options: [ "yes", "no" ]
  }
]

modelName将保存结果,followUps依赖selects,如果答案为condition,则显示{。}}。

然后,您可以使用ng-repeat循环遍历此数组。 请注意以下代码为Jade

div.question(ng-repeat="select in selects")
  span.title {{select.title}}
  select(ng-model="results[select.modelName]", 
         ng-options="option for option in select.options")
  div.subquestion(ng-repeat="subselect in select.followUps", 
                  ng-show="!subselect.condition || 
                            subselect.condition == results[select.modelName]")
    span.title {{subselect.title}}
    select(ng-model="results[subselect.modelName]", 
       ng-options="option for option in subselect.options")

基本上你正在做的是重复你的title,然后是select填充options(使用ng-options),以及所有followUps }选择,但我们根据答案是否与followUp匹配,使用condition指令来控制ng-show选择的可见性。

这可以显着加强(用模板制作你自己的指令),也可以容忍followUps的无数层,但希望这会让你走上正确的轨道?

this plunker 中查看它。

答案 1 :(得分:1)

以下是来自盐湖城AngularJS会议的精彩视频......他在20分钟内介绍了您感兴趣的一些内容。

http://youtu.be/tnXO-i7944M?t=15m20s

AJAX请求属于工厂,该工厂作为依赖项注入控制器。

编辑:所以完全错过了你的问题的内容,抱歉。您可以使用ng-repeat指令设置select,如下所示:

<select ng-repeat="select in selects">
  <option ng-repeat="option in select.options" handle-fetch-select>{{ option }}</option>
</select>

app.factory('selectFactory', function (['$http']){
    var factory = {};

    factory.getSelects = function(){
        return $http.get('/selects.json');
    }

    factory.getSomeOtherSelect = function(){
        return $http.get('/otherSelects.json');
    }

    return factory;
});

app.controller('SelectController', function( ['$scope', 'selectFactory'] ){
    $scope.selects = [];

    init();

    function init(){
        selectFactory.getSelects().success(function(data){
            //would be $scope.selects = data; just mocking a response
            $scope.selects = [ { label : 'Foo', options : ['opt1', 'opt2', 'opt3']} ]};
        });
    }
});

app.directive('handleFetchSelect', function(['$scope', 'selectFactory']){
   return function(scope, element, attrs){
       element.bind('click', function(){
           //
           //Add logic to determine if a fetch is required or not
           // 
           //if (noFetchRequired)
           //    return;

           //determine which selects to request from server
           switch (expression) {
               case (expression1) :
                   selectFactory.getSomeOtherSelect.success(function(returnedArrayOfSelects){
                       scope.apply(function(returnedArrayOfSelects){
                           scope.selects.concat(returnedArrayOfSelects); 
                       });
                   }).error(function(){});
                   break;
           }
       }
   })
});

没有调试这个存根... ...&lt; - disclaimer :)希望你明白这一点。