2013-03-08 19 views
11

chcę renderować formularz, opartej na dynamicznej konfiguracji pola:Jak używać pola Angular do wyświetlania dynamicznych pól formularzy?

$scope.fields = [ 
    { title: 'Label 1', type: 'text', value: 'value1'}, 
    { title: 'Label 2', type: 'textarea', value: 'value2'} 
]; 

powinno to wyświetli coś że zachowuje się jak:

<div> 
    <label>{{field.title}}<br /> 
     <input type="text" ng-model="field.value"/> 
    </label> 
</div> 
<div> 
    <label>{{field.title}}<br /> 
     <textarea ng-model="field.value" rows="5" cols="50"></textarea> 
    </label> 
</div> 

Proste wdrożenie byłoby użyć if sprawozdań do uczynienia szablony dla każdego typu pola. Jednakże, ponieważ Angular nie obsługuje stwierdzeń if, jestem liderem w kierunku dyrektyw. Moim problemem jest zrozumienie, jak działa powiązanie danych. Model documentation for directives jest nieco gęsty i teoretyczny.

Mam wyśmiewali się przykładem szkielety, co staram się zrobić tutaj: http://jsfiddle.net/gunnarlium/aj8G3/4/

Problem polega na tym, że pola formularza nie są zobowiązane do modelu, więc $ scope.fields w submit () nie jest aktualizowany. Podejrzewam, że treść mojej funkcji dyrektywy jest całkiem źle ... :)

Idąc dalej, muszę również wspierać inne typy pól, jak przyciski radiowe, pola wyboru, wybiera itd

+0

Prawdopodobny duplikat [AngularJS: nie można zmienić typu wejścia] (http://stackoverflow.com/questions/15148456/angularjs-cant-change-input-type) – Aides

Odpowiedz

22

Pierwszy problem jesteś uruchomiony niezależnie od dyrektywy, którą próbujesz utworzyć, używając polecenia ng-repeat w formularzu z elementami formularza. Może być problem z tym, jak ng-repeat tworzy nowy zakres.

This directive creates new scope.

Polecam też zamiast używać element.html że używasz ngSwitch zamiast w częściowym szablonu.

<div class="form-row" data-ng-switch on="field.type"> 
    <div data-ng-switch-when="text"> 
     {{ field.title }}: <input type="text" data-ng-model="field.value" /> 
    </div> 
    <div data-ng-switch-when="textarea"> 
     {{ field.title }}: <textarea data-ng-model="field.value"></textarea> 
    </div> 
</div> 

to nadal pozostawia cię z problemem modyfikacji elementów formularza w zakresie dziecięcej powodu NG-repeat i za to proponuję przy użyciu metody ngChange na każdy element, aby ustawić wartość, gdy element uległ zmianie. Jest to jeden z niewielu elementów, które moim zdaniem AngularJS radzi sobie bardzo dobrze w tym momencie.

+0

W rzeczywistości ngSwitch był dokładnie tym, czego potrzebowałem. Nie napotkano problemów z zasięgiem :) (jeszcze). Wciąż nie całkiem rozumiem dyrektywy, ale to jest zadanie na inny dzień. –

+0

@GunnarLium Czy byłeś w stanie rozwiązać ten problem? Próbuję zaimplementować podobne rozwiązanie, ale utknąłem z powodu dokładnie takich samych problemów.Zastanawiasz się, czy możesz podzielić się swoimi spostrzeżeniami, jeśli/jak rozwiązałeś problem – user6123723

4

Możesz wziąć pod uwagę Metawidget. Używa schematu JSON, ale poza tym jest bardzo blisko twojego przypadku użycia. Cała próbka:

<html ng-app="myApp"> 
    <head> 
     <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script> 
     <script src="http://metawidget.org/js/3.5/metawidget-core.min.js" type="text/javascript"></script> 
     <script src="http://metawidget.org/js/3.5/metawidget-angular.min.js" type="text/javascript"></script> 
     <script type="text/javascript"> 
      angular.module('myApp', [ 'metawidget' ]) 
       .controller('myController', function($scope) { 

        $scope.metawidgetConfig = { 
         inspector: function() { 
          return { 
           properties: { 
            label1: { 
             type: 'string' 
            }, 
            label2: { 
             type: 'string', 
             large: true 
            } 
           } 
          } 
         } 
        } 

        $scope.saveTo = { 
         label1: 'value1', 
         label2: 'value2' 
        } 

        $scope.save = function() { 
         console.log($scope.saveTo); 
        } 
       }); 
     </script> 
    </head> 
    <body ng-controller="myController"> 
     <metawidget ng-model="saveTo" config="metawidgetConfig"> 
     </metawidget> 
     <button ng-click="save()">Save</button> 
    </body> 
</html> 
0

Atrybut type można zmienić, gdy element jest z DOM, więc dlaczego nie mały dyrektywa, która usuwa go z DOM, zmienia go wpisać, a następnie włożyć z powrotem do tego samego miejsca?

Opcja $watch jest opcjonalna, ponieważ cel można zmienić dynamicznie raz i nie zmieniać.

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

 
app.controller('MainCtrl', function($scope) { 
 
    $scope.rangeType = 'range'; 
 
    $scope.newType = 'date' 
 
}); 
 

 
app.directive('dynamicInput', function(){ 
 
    return { 
 
     restrict: "A", 
 
     link: linkFunction 
 
    }; 
 
    
 
    function linkFunction($scope, $element, $attrs){ 
 
     
 
     if($attrs.watch){ 
 
     $scope.$watch(function(){ return $attrs.dynamicInput; }, function(newValue){ 
 
      changeType(newValue); 
 
     }) 
 
     } 
 
     else 
 
     changeType($attrs.dynamicInput); 
 
     
 
     
 
     function changeType(type){ 
 
     var prev = $element[0].previousSibling; 
 
     var parent = $element.parent(); 
 
     $element.remove().attr('type', type); 
 
     if(prev) 
 
      angular.element(prev).after($element); 
 
     else 
 
      parent.append($element); 
 
     } 
 
    } 
 
});
span { 
 
font-size: .7em; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div ng-app="app" ng-controller="MainCtrl"> 
 
    <h2>Watching Type Change</h2> 
 
    Enter Type: <input ng-model="newType" /><br/> 
 
    Using Type (with siblings): <span>Before</span><input dynamic-input="{{newType}}" watch="true" /><span>After</span><Br> 
 
    Using Type (without siblings): <div><input dynamic-input="{{newType}}" watch="true" /></div> 
 
    
 
    <br/><br/><br/> 
 
    <h2>Without Watch</h3> 
 
    Checkbox: <input dynamic-input="checkbox" /><br /> 
 
    Password: <input dynamic-input="{{ 'password' }}" value="password"/><br /> 
 
    Radio: <input dynamic-input="radio" /><br/> 
 
    Range: <input dynamic-input="{{ rangeType }}" /> 
 
</div>

Testowany w najnowszym Chrome i IE11.

Powiązane problemy