N级层次结构Array Angular JS

时间:2015-08-21 04:22:36

标签: javascript arrays angularjs

我正在写一份问卷调查申请,有回答的问题,这些回答可能有孩子问题,这些问题可能有另一个孩子问题的回答,然后是N级层次结构,我需要找到最好的策略加载到html列表中,使用正常的ng-repeat我有一个级别的限制,在this example我链4个级别,但它可能更多,我感谢任何评论或建议。

var myApp = angular.module('myApp',[]);
myApp.controller('myCtrl',function ($scope){
$scope.questionnaire = [
    {
        QuestionID: 1,
        Description: "Question 1",
        Responses: [{
            RespDescription: "Response 1"
        },
        {
            RespDescription: "Response 2",
            ChildQuestions: [{
                QuestionID: 2,
                Description: "Child Question 2.1",
                Responses: [{
                    RespDescription: "Child Response 2.1.1"
                },
                {
                    RespDescription: "Child Response 2.1.2",
                    ChildQuestions: [{
                        QuestionID: 3,
                        Description: "Child Question 2.1.2.1",
                        Responses:[{
                            RespDescription: "Child Response...",
                            ChildQuestions:[{
                                QuestionID:4,
                                Description: "Other Child Question",
                                Responses:[{
                                    RespDescription: "Response..."
                                }]

                            }]
                        }]
                    }]
                }]
            }]
        }]
    }
];

})

2 个答案:

答案 0 :(得分:0)

我已经完成了一个类似的问卷调查类型应用程序。我所要做的就是创建一个具有树状结构关系的后端api。

你希望将它连接到后端并且不仅仅是写出来,否则它会变得非常混乱,很像回调地狱。

Here是github上项目的开始。它使用环回进行数据建模并挂钩到角度前端,但您可以以任何方式使用后端。

idea是当您查询第一个question时,它有一些孩子answers。然后,每个答案都附加了另一个问题,依此类推,依此类推。每个模型的关系在这里都很重要。

通过这种方式,您可以创建一个控制器,当您选择answerA的answerC时,它会在数据库中查询相关的questionC对象,并包含与该新问题C相关联的所有答案。

然后,您将添加新加载的questionC及其对主要问题数组的回答并向下滚动(或类似的内容)。

一个快速的sudo代码示例:

//controller.js
app.controller('questionair', function(Answer, Question){
  //Lets load our first question, with the related 3 answers
  Question.findById({id: 1}, {include: 'answers'}).$promise
    .then(function(question){
      $scope.questions = [question];
    });

  //function that gets new question from our select answer
  $scope.answerMe = function(questionId){
    Question.findById({id: questionId}, {include: 'answers'}).$promise
      .then(function(newQuestion){
        $scope.questions.push(newQuestion);
      },function(error){
        console.log('You\'ve answered the last question!');
      });
  };
});

//index.html
<div ng-repeat="question in questions">
   <h2>{{ question.text }}</h2>
   <ul>
     <li ng-repeat="answer in question.answers" 
         ng-click="answerMe(answer.questionId)">
       {{ answer.text }}
     </li>
   </ul>
</div>

答案 1 :(得分:0)

我是通过Mark Lagendijk的code in plunker并且他有这个任务的解决方案,递归是秘密,有一个指令调用本身可能代表一个N级结构,关键是名为的服务RecursionHelper 编译并避免指令中的无限循环,我根据自己的需要调整了代码,这就是结果:

RecursionHelper

/* 
 * An Angular service which helps with creating recursive directives.
* @author Mark Lagendijk
* @license MIT
*/
angular.module('RecursionHelper', []).factory('RecursionHelper', ['$compile', function($compile){
return {
    /**
     * Manually compiles the element, fixing the recursion loop.
     * @param element
     * @param [link] A post-link function, or an object with function(s) registered via pre and post properties.
     * @returns An object containing the linking functions.
     */
    compile: function(element, link){
        // Normalize the link parameter
        if(angular.isFunction(link)){
            link = { post: link };
        }

        // Break the recursion loop by removing the contents
        var contents = element.contents().remove();
        var compiledContents;
        return {
            pre: (link && link.pre) ? link.pre : null,
            /**
             * Compiles and re-adds the contents
             */
            post: function(scope, element){
                // Compile the contents
                if(!compiledContents){
                    compiledContents = $compile(contents);
                }
                // Re-add the compiled contents to the element
                compiledContents(scope, function(clone){
                    element.append(clone);
                });

                // Call the post-linking function, if any
                if(link && link.post){
                    link.post.apply(null, arguments);
                }
            }
        };
    }
};
}]);

questionTree指令:

directives.directive('questionTree', function (RecursionHelper) {
return {
    restrict: "AE",
    scope: {
        items: "=",
    },
    priority: 500,
    replace: true,
    //I use templateURL but for simplicity I used inline template in this code
    template: function (el, attr) {
        var itemType = attr["itemType"];

        if (itemType == "question") {
            return '<ul>'+
                     '<li ng-repeat="item in items">'+
                         '<div ng- click="loadChildResponses(item);$event.stopPropagation();">{{item.Description}}</div>'+
    '<question-tree items="item.Responses" item-type="reponse"></question-tree>'+
                     '</li>'+
                   '</ul>';

        }
        else {
            return '<ul>'+
                       '<li ng-repeat="item in items">'+
                           '<div ng-click="loadChildQuestions(item);$event.stopPropagation();">{{item.Description}}</div>'+
                           '<question-tree items="item.ModelWizardQuestions" item-type="question"></question-tree>'+
                        '</li>'+
                      '</ul>';

        }

    },
    controller: function ($scope, $http) {
        $scope.loadChildResponses = function (item) {



            $http.get(siteUrls.GetReponses + "?QuestionID=" + item.QuestionID)
           .success(function (data) {
               if (data && data.length > 0) {
                   item.Responses = data;
               }
           });
        };

        $scope.loadChildQuestions = function (item) {



            $http.get(siteUrls.getChildQuestions + "?ResponseID=" + item.ResponseID)
           .success(function (data) {
               if (data && data.length > 0) {
                   item.Questions = data;
               }
           });
        };
    },
    compile: function (element) {
        // Use the compile function from the RecursionHelper,
        // And return the linking function(s) which it returns
        return RecursionHelper.compile(element);
    }
}
});

所以,我加载第一级问题,并附上questionTree指令,应用程序可以加载N级。

HTML:

 <ul>
   <li ng-repeat="question in Questions">{{question.Description}}
      <ul>
         <li ng-repeat="response in question.Responses"><span>{{response.Description}}</span>
           <question-tree items="response.Questions" item-type="question"></question-tree>
          </li>
       </ul>
    </li>
 </ul>