2014-02-04 3 views
0

Я генерирую вложенную форму из объекта json say formObject и связывая значения в самом объекте json. Я разбираю значения рекурсивно и вытаскиваю фактические данные, например, dataObject при отправке.Данные привязки к модели для динамических вложенных форм в angularjs

Я могу получить dataObject в линейной форме, подобной этой. http://jsfiddle.net/DrQ77/80/.

<select ng-model="Answers[question.Name]" ng-options="option for option in question.Options"> 

В отличии от вышесказанного, http://jsfiddle.net/DrQ77/92/ имеют некоторые рекурсии. Я переименовал question в element, чтобы представить оба вопроса: & разделы. У каждого раздела может быть несколько вопросов &, несколько разделов (это то, что я подразумевал под гнездованием). В конце концов, я хочу, чтобы объект был в форме ниже с любым уровнем вложенности.

Answers=[{ 
    section:"Personal", 
    values:[{GenderQuestion:"Male"},{MaritalStatus:"Married"},{section:"Sub Personal",values:[{LivingWith:"Alone"}]}] 
}, { 
    section:"Random", 
    values:[{ColorQuestion:"Red"}], 
}, 
{SectionLess:"opt1"}] 

Это одно решение & я могу получить его представить, $ scope.Answers с первой скрипкой не (я думаю) позволяют такого рода вложенности. Но когда мне нужно обновить существующий объект dataObject, мне было необходимо сопоставить объекты данных с объектом formObject перед его рендерингом, а затем снова разобрать на submit. Теперь это не MVC, не выглядит элегантно (из-за рекурсии) & Я думаю, что для этого есть «угловой способ».

Пробовал ли кто-нибудь это &, работал ли он лучше? Как мне обойти это?

+2

Я не совсем понял проблему с вашим подходом. Может быть, это потому, что пример JSFiddle недостаточно сложный - нет упоминаемой «рекурсии» и необходимости «разбора» на submit '- '$ scope.Answers постоянно обновляется и готово к отправке в любое время , из-за привязки данных Angular. Но может быть, это потому, что я слишком сонлив :) В любом случае, было бы здорово, если бы вы могли сделать скрипку более развитой (но не слишком большой - привет-мировой стиль), чтобы полностью проиллюстрировать недостатки вашего нынешнего подхода. – vucalur

+2

Как сказал @vucalur, я тоже не совсем понимаю, в чем проблема в скрипке. Я также не вижу рекурсии в примере. Можете ли вы обновить свой вопрос и лучше объяснить, каковы ваши проблемы? – Beyers

+0

Да, попытался объяснить немного! Извините за то, что вы не разработали заявление о проблеме в первый раз, у меня странные идеи о краткости! – aksci

ответ

1

Не очень красиво, но это альтернатива решению, которое вы уже предложили.

http://jsfiddle.net/DrQ77/84/

function QuestionController($scope) { 
    $scope.answers = {}; 
    $scope.tempOption = ""; 
    $scope.questions = [ 
    { 
     "text": "Gender?", 
     "name": "GenderQuestion", 
     "options": ["Male", "Female"]}, 
    { 
     "text": "Favorite color?", 
     "name": "ColorQuestion", 
     "options": ["Red", "Blue", "Green"]} 
    ]; 

    $scope.showAnswers = function() { 
     console.log($scope.answers); 
    }; 

    $scope.pumpOption = function (name, tempOption) { 
     $scope.answers[name] = tempOption; 
    }; 
}; 

<ul ng-repeat="question in questions"> 
    <li> 
     <div>{{question.text}}</div> 
     <select ng-model="tempOption" ng-options="opt for opt in question.options" ng-change="pumpOption(question.name, tempOption)"> 
     </select> 
    </li> 
</ul>  

Мы связываем значение выбранного параметра в выберите тег в переменной $ scope.tempOption.

Затем мы прослушиваем событие изменения ng в этом теге select, где мы запускаем функцию, которая принимает переменную $ scope.tempOption плюс {{question.name}}, связанную с тегом select.

Эта функция затем устанавливает ответы [имя] на текущее значение $ scope.tempOption.

Надеется, что это работает для вас, удач :)

+1

Да, это работает, но все выглядит очень уродливо при рекурсии, когда у меня есть данные json с вложенными объектами. В настоящее время у меня есть [решение вроде] (http://jsfiddle.net/2AwLM/23/), но это не MVC, и есть небольшая работа над обновлением полей через одну и ту же форму. – aksci

0

просто создать $scope.Answer = {}; и хорды нг-модель для него. http://jsfiddle.net/2AwLM/40/

+0

Да, это один из способов, но он все еще не отвечает на проблему гнездования. Например. Я не могу использовать 'Answers [0] .values ​​[0] .GenderQuestion', не ссылаясь на его элемент' Answer [0] .values ​​[0] '. – aksci

0

ОК - это было не так тривиально, как я думал сначала, поэтому я надеюсь, что это то, что вам нужно, - вы захотите использовать директиву, которая динамически генерирует свой шаблон HTML (еще лучше использовать templateUrl и функция, которая проходит по типу)

TLDR: Смотрите скрипку в http://jsfiddle.net/cirrusinno/SzaNW/2

HTML, довольно просто

<div ng-controller="questionsController"> 

<!-- for each question, render section or question --> 
<div ng-repeat="item in Questions"> 
    <!-- we ignore section here as it's a root section --> 
    <question item="item"></question> 
</div> 

Вам необходимо создать директиву, которая может отображать оба вопроса: &.Кроме того, нужно будет следить секции, чтобы он мог построить ответы

.directive('question', ['$compile', '$templateCache', function ($compile, $templateCache) { 
    var generateHtmlTemplate = function (item, section) { 
     return item.type != 'section' ? 
     // render the question  
     'question ' + item.name + '<br/>' + 
      '<select ng-model="optionValue" ng-options="opt for opt in item.options" ng-change="pushAnswer(item.name, section, optionValue)"></select>' : 
     // or the template for a section 
     '<br/><hr/>section ' + item.sectionName + '<br/>' + 
      '<div ng-repeat="q in item.questions"><question item="q" section="item"></question></div><hr/>'; 
    } 

    var currentSection = null; 

    return { 
     scope: { 
      item: '=', 
      section: '=' 
     }, 
     restrict: 'E', 
     link: function ($scope, element, attrs) { 
      // check current section 
      if ($scope.item.type == 'section') { 
       // set new current section 
       $scope.currentSection = $scope.item; 
      } else { 
       // use section passed in from parent section 
       $scope.currentSection = $scope.section; 
      } 

      // get template html 
      var t = generateHtmlTemplate($scope.item, $scope.currentSection); 

      // set the scope function to set the value 
      $scope.pushAnswer = function (q, section, value) { 
       // build the Answers object here however you want... 
       if (section != null) { 
        console.log('pushAnswer q=' + q.name + ' - section=' + section.sectionName + ' - value=' + value); 
       } else { 
        console.log('pushAnswer q=' + q.name + ' - section=rootSection - value=' + value); 
       } 

      }; 

      // chuck it into element as template 
      element.html(t); 

      // compile it up and return it 
      $compile(element.contents())($scope); 
     }, 
    }; 
}]) 
+0

Хорошо, но отображение существующей модели является проблемой. Я думал о создании директив для отдельных элементов для вставки родительского модельного объекта для вложенного элемента в ng-model. Думаю, я должен попробовать это! – aksci

+0

Я только что использовал существующую модель, которая была дана в других вопросах - если у вас есть отдельная модель, отправьте ее, и мы применим ее к этой директиве. В любом случае директива будет развернута в модели. Создание директивы «один размер подходит всем» было бы гораздо более сложной задачей. Я также думал об использовании двух директив, один для раздела, один для вопросов, но я начал использовать его, и он просто работает постепенно. Возможно, две директивы были бы более чистыми, так как переменные области видимости были бы немного чище (т.е.: секция не нуждается в currentSection, она просто передает ее в дочерний вопрос). – leon

1
var model = { 
    colors:["Red","Blue","Green","Black","White"], 
    genders:["Male", "Female"], 
    topic:["Gender", "Color"], 
    category:["Favorite", "Least favorite"], 
}; 

function makeQuestion(topic, category){ 
    return (category+1 ? model.category[category] + ' ' : '') 
    + ' ' + model.topic[topic] + '?' 
} 

function QuestionController($scope){ 

    $scope.Answers = {}; 
    $scope.Questions = [ 
     { 
      "Text": makeQuestion(0), 
      "Name": "GenderQuestion", 
      "Options": model.genders 
     },{ 
      "Text": makeQuestion(1,0), 
      "Name": "ColorQuestion", 
      "Options": model.colors.slice(0,3) 
     },{ 
      "Text": makeQuestion(0,1), 
      "Name": "SexistQuestion", 
      "Options": model.genders 
     },{ 
      "Text": makeQuestion(1,1), 
      "Name": "RacistQuestion", 
      "Options":model.colors.slice(3) 
     } 
    ]; 

    $scope.ShowAnswers = function() 
    { 
     console.log($scope.Answers); 
    }; 
}  

Хорошо, я шучу вокруг. Но вы пытались использовать плоский родственный реляционный подход к таблице вместо вложенных?

{ 
    sections:[ 
    { "Name": 'Personal', "questions":[0], sub:[1] }, 
    { "Name": 'SubPersonal', "questions":[3], sub:[]}, 
    { "Name": 'Random', "questions":[1,2], sub:[] } 
    ], 
    questions:[ 
    { "Name":"Gender",  "Text":"Gender?",   "Options":["Male", "Female"] }, 
    { "Name":"Color",  "Text":"Favorite Color?", "Options":["Red","Blue","Green"] }, 
    { "Name":"LivingWith", "Text":"Living With?", "Options":["Alone","Someone"] }, 
    { "Name":"Random",  "Text":"SectionLess",  "Options":["opt1", "opt2"] } 
    ] 
} 
+0

Да, но опять же, мне нужно будет что-то написать для создания исходного объекта. Я не хочу представлять свои модели данных в плоских таблицах! – aksci

+0

Как еще вы ожидаете написать рекурсивное отношение объекта JSON? Я имею в виду, есть причина, по которой JSON.stringify не разрешает круговые ссылки. Parent = {child: {parent: {child: {parent: {child: {посмотреть, что я имею в виду?}}}}}} – Julian

Смежные вопросы