2013-08-22 3 views
0

Я работаю над создателем угловой формы, который генерирует json. Все работает отлично, за исключением одного.Угловая: как повторно отобразить скомпилированный шаблон после обновления модели?

Вы можете найти пример здесь: http://jsfiddle.net/dJRS5/8/

HTML:

<div ng-app='app'> 
    <div class='formBuilderWrapper' id='builderDiv' ng-controller="FormBuilderCtrl" > 
     <div class='configArea' data-ng-controller="elementDrag">  
      <h2>drag/drop</h2> 
      <form name="form" novalidate class='editBloc'> 
       <div data-ng-repeat="field in fields" class='inputEdit'> 
        <data-ng-switch on="field.type"> 
         <div class='labelOrder' ng-class='{column : !$last}' drag="$index" dragStyle="columnDrag" drop="$index" dropStyle="columnDrop">{{field.type}} 
         </div> 
         <label for="{{field.name}}" data-ng-bind-html-unsafe="field.caption"></label> 

         <input data-ng-switch-when="Text" type="text" placeholder="{{field.placeholder}}" data-ng-model="field.value" /> 

         <p data-ng-switch-when="Text/paragraph" data-ng-model="field.value" data-ng-bind-html-unsafe="field.paragraph"></p> 

          <span data-ng-switch-when="Yes/no question"> 
           <p data-ng-bind-html-unsafe="field.yesNoQuestion"></p> 
           <input type='radio' name="yesNoQuestion" id="yesNoQuestion_yes" value="yesNoQuestion_yes" /> 
           <label for="yesNoQuestion_yes">Oui</label> 
           <input type='radio' name="yesNoQuestion" id="yesNoQuestion_no" value="yesNoQuestion_no"/> 
           <label for="yesNoQuestion_no">Non</label> 
          </span>  
      <p data-ng-switch-when="Submit button" class='submit' data-ng-model="field.value"> 
        <input value="{{field.name}}" type="submit"> 
       </p>       
        </data-ng-switch> 
       </div> 
      </form> 
     </div>   
     <div id='previewArea' data-ng-controller="formWriterCtrl"> 
      <h2>preview</h2>  
      <div data-ng-repeat="item in fields" content="item" class='templating-html'></div> 
     </div>   
    </div> 
</div> 

JS:

var app = angular.module('app', []); 

    app.controller('FormBuilderCtrl', ['$scope', function ($scope){ 
     $scope.fields = [{"type":"Text/paragraph","paragraph":"hello1"},{"type":"Yes/no question","yesNoQuestion":"following items must be hidden","yes":"yes","no":"no"},{"type":"Text/paragraph","paragraph":"hello2"},{"type":"Submit button","name":"last item"}] ; 
    }]); 


    app.controller('elementDrag', ["$scope", "$rootScope", function($scope, $rootScope, $compile) { 
     $rootScope.$on('dropEvent', function(evt, dragged, dropped) { 
      if($scope.fields[dropped].type == 'submitButton' || $scope.fields[dragged].type == 'submitButton'){ 
       return; 
      } 
      var tempElement = $scope.fields[dragged]; 
      $scope.fields[dragged] = $scope.fields[dropped]; 
      $scope.fields[dropped] = tempElement; 
      $scope.$apply(); 
     }); 
    }]); 

    app.directive("drag", ["$rootScope", function($rootScope) { 
     function dragStart(evt, element, dragStyle) { 
      if(element.hasClass('column')){ 
       element.addClass(dragStyle); 
       evt.dataTransfer.setData("id", evt.target.id); 
       evt.dataTransfer.effectAllowed = 'move'; 
      } 
     }; 
     function dragEnd(evt, element, dragStyle) { 
      element.removeClass(dragStyle); 
     }; 
     return { 
      restrict: 'A', 
      link: function(scope, element, attrs) { 
       if(scope.$last === false){ 
        attrs.$set('draggable', 'true'); 
        scope.dragStyle = attrs["dragstyle"]; 
        element.bind('dragstart', function(evt) { 
         $rootScope.draggedElement = scope[attrs["drag"]]; 
         dragStart(evt, element, scope.dragStyle); 
        }); 
        element.bind('dragend', function(evt) { 
         dragEnd(evt, element, scope.dragStyle); 
        }); 
       } 
      } 
     } 
    }]); 

    app.directive("drop", ['$rootScope', function($rootScope) { 
     function dragEnter(evt, element, dropStyle) { 
      element.addClass(dropStyle); 
      evt.preventDefault(); 
     }; 
     function dragLeave(evt, element, dropStyle) { 
      element.removeClass(dropStyle); 
     }; 
     function dragOver(evt) { 
      evt.preventDefault(); 
     }; 
     function drop(evt, element, dropStyle) { 
      evt.preventDefault(); 
      element.removeClass(dropStyle); 
     }; 
     return { 
      restrict: 'A', 
      link: function(scope, element, attrs) { 
       if(scope.$last === false){ 
        scope.dropStyle = attrs["dropstyle"]; 
        element.bind('dragenter', function(evt) { 
         dragEnter(evt, element, scope.dropStyle); 
        }); 
        element.bind('dragleave', function(evt) { 
         dragLeave(evt, element, scope.dropStyle); 
        }); 
        element.bind('dragover', dragOver); 
        element.bind('drop', function(evt) { 
         drop(evt, element, scope.dropStyle); 
         var dropData = scope[attrs["drop"]]; 
         $rootScope.$broadcast('dropEvent', $rootScope.draggedElement, dropData); 
        }); 
       } 
      } 
     } 
    }]); 



    app.controller('formWriterCtrl', ['$scope', function ($scope){ 

    }]); 


    app.directive('templatingHtml', function ($compile) { 
     var previousElement; 
     var previousIndex; 
     var i=0; 
     var inputs = {}; 

     var paragraphTemplate = '<p data-ng-bind-html-unsafe="content.paragraph"></p>';  
     var noYesQuestionTemplate = '<p data-ng-bind-html-unsafe="content.yesNoQuestion"></p><input id="a__index__yes" type="radio" name="a__index__"><label for="a__index__yes" />{{content.yes}}</label><input id="a__index__no" class="no" type="radio" name="a__index__" /><label for="a__index__no">{{content.no}}</label>'; 
     var submitTemplate = '<p class="submit"><input value="{{content.name}}" type="submit" /></p>'; 

     var getTemplate = function(contentType, contentReplace, contentRequired) { 
      var template = ''; 
      switch(contentType) { 
       case 'Text/paragraph': 
        template = paragraphTemplate; 
        break; 
       case 'Yes/no question': 
        template = noYesQuestionTemplate; 
        break; 
      case 'Submit button': 
        template = submitTemplate; 
        break; 
      } 

      template = template.replace(/__index__/g, i);   
      return template; 
     } 

     var linker = function(scope, element, attrs) { 
      i++; 
      elementTemplate = getTemplate(scope.content.type); 
      element.html(elementTemplate); 
      if(previousElement == 'Yes/no question'){ 
       element.children().addClass('hidden'); 
       element.children().addClass('noYes'+previousIndex); 
      } 
      if(scope.content.type == 'Yes/no question'){ 
       previousElement = scope.content.type; 
       previousIndex = i; 
      } 
      $compile(element.contents())(scope); 
     } 

     return { 
      restrict: "C", 
      link: linker, 
      scope:{ 
       content:'=' 
      } 
     }; 
    }); 

На примере есть 2 зоны: - первый делает ngRepeat на Json и разрешить переупорядочивать элементы с перетаскиванием - вторая область также выполняет ngRepeat, это предварительный просмотр с помощью функции компиляции. Некоторые элементы скрыты, если они после того, что я назвал «Да/нет вопроса»

Вот пример Json, порожденная формы строителя:

$scope.fields = 

[{"type":"Text/paragraph","paragraph":"hello1"},{"type":"Yes/no question","yesNoQuestion":"following items must be hidden","yes":"yes","no":"no"}, 
{"type":"Text/paragraph","paragraph":"hello2"},{"type":"Submit button","name":"last item"}] ; 

Когда страница загрузки все в порядке, hello1 является видимый и Hello2 скрыт.

Но когда я отбрасываю Hello1 после «Да/нет вопросов», элементы dom реорганизуются, но Hello1 не скрывается. Я думаю, что он исходит из компиляции $, но я не знаю, как его решить.

Не могли бы вы помочь мне с этим, пожалуйста?

Спасибо

ответ

1

Я только вижу, что вы не устанавливая «скрытый» класс на элемент на основе этого правила (после того, как да/нет) в функции связи. Это называется только один раз для элемента DOM - когда он впервые создан. Обновление модели данных не воссоздает элемент, а обновляет его. Вам понадобится механизм, который его воссоздает, если вы хотите сделать это таким образом.

Я вижу три пути вы можете сделать это:

  1. В функции линкера, прослушивающие же dropEvent, что вы слушаете для выше. Это более эффективно, чем вы думаете (это очень быстро), и вы можете переоценить, применять ли этот класс hidden или нет.

  2. Используйте что-то вроде ngIf или буквально пересоздайте его в своей коллекции, чтобы заставить элемент полностью воссоздать. Это не так эффективно, но иногда по-прежнему желательно по разным причинам.

  3. Если ваш вариант использования на самом деле прост (если это не было чем-то более сложным, чем вы пытаетесь сделать), вы можете использовать CSS, чтобы сделать что-то вроде этого. Простое правило, такое как

    .yes-no-question + .text-paragraph { display: none; } 
    

    0 0 Это гораздо более ограничено тем, что он может сделать, очевидно, но это самый эффективный вариант, если он охватывает то, что вам нужно.

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