एंगुलरजेएस के साथ एक रूप में गतिशील सत्यापन और नाम


98

मेरे पास यह फॉर्म है: http://jsfiddle.net/dfJeN/

जैसा कि आप देख सकते हैं कि इनपुट के लिए नाम मान सांख्यिकीय रूप से निर्धारित है:

name="username"

, फॉर्म सत्यापन ठीक काम करता है (कुछ जोड़ें और इनपुट से सभी पाठ हटा दें, एक पाठ प्रकट होना चाहिए)।

फिर मैं नाम मान को गतिशील रूप से सेट करने का प्रयास करता हूं: http://jsfiddle.net/jNWB8/

name="{input.name}"

फिर मैं इसे अपने सत्यापन के लिए लागू करता हूं

login.{{input.name}}.$error.required

(यह पैटर्न एनजी-रिपीट में उपयोग किया जाएगा) लेकिन मेरा फॉर्म सत्यापन टूट गया है। मेरे ब्राउज़र में इसकी सही ढंग से व्याख्या की गई है (यदि मैं उस तत्व का निरीक्षण करता हूं जिसे मैंने login.username देखा। $ error.required)।

कोई उपाय ?

संपादित करें: कंसोल में गुंजाइश लॉग करने के बाद ऐसा प्रतीत होता है कि ए

{{input.name}}

अभिव्यक्ति प्रक्षेप नहीं है। मेरा फॉर्म {{input.name}} विशेषता के रूप में है, लेकिन उपयोगकर्ता नाम नहीं।

अद्यतन: 1.3.0-rc.3 नाम = "{{input.name}}" के बाद से अपेक्षा के अनुरूप काम करता है। कृपया # 1404 देखें


कुछ शोध के बाद मैंने यह पाया: "एक बार परिदृश्य जिसमें ngBind का उपयोग {{अभिव्यक्ति}} से अधिक पसंद किया जाता है, जब बाइंडिंग को टेम्प्लेट में प्रदर्शित करना वांछनीय है, जो कि अंगुली के कंपाउंड से पहले इसकी कच्ची अवस्था में ब्राउज़र द्वारा प्रदर्शित किया जाना वांछनीय है" । इस पृष्ठ में docs.angularjs.org/api/ng.directive:ngBind , मैं जो करने की कोशिश कर रहा हूं , उसके लिए यह एक अच्छी शुरुआत है। अगर मुझे कोई हल मिल जाए तो यह पोस्ट अपडेट हो जाएगी।
IxDay

एक खुला गितुब मुद्दा है github.com/angular/angular.js/issues/1404
यारोस्लाव

क्या किसी भी उत्तर ने आपकी समस्या हल कर दी है। यदि ऐसा है, तो कृपया इसे स्कोर के रूप में cckckmark bellow पर क्लिक करके उत्तर के रूप में चिह्नित करें।
रिकार्डो सूज़ा

यहाँ एक ब्लॉग लेख है जो संभवतः इस मुद्दे पर आने वाले अन्य लोगों के लिए कुछ मदद करेगा: thebhwgroup.com/blog/2014/08/angularjs-html-form-design-part-2
PFranchise

जवाबों:


176

आप वैसा नहीं कर सकते जैसा आप कर रहे हैं।

यह मानते हुए कि आप क्या करने की कोशिश कर रहे हैं, क्या आपको गतिशील रूप से तत्वों को जोड़ने की जरूरत है, एनजी-रिपीट जैसी किसी चीज के साथ, आपको उन व्यक्तिगत वस्तुओं के सत्यापन की अनुमति देने के लिए नेस्टेड एनजी-फॉर्म का उपयोग करने की आवश्यकता है :

<form name="outerForm">
<div ng-repeat="item in items">
   <ng-form name="innerForm">
      <input type="text" name="foo" ng-model="item.foo" />
      <span ng-show="innerForm.foo.$error.required">required</span>
   </ng-form>
</div>
<input type="submit" ng-disabled="outerForm.$invalid" />
</form>

अफसोस की बात है, यह सिर्फ कोणीय की एक अच्छी तरह से प्रलेखित सुविधा नहीं है।


11
आपने अंत में इसे कैसे हल किया? मैं अब भी नहीं देखता कि यह विशेष उत्तर आपकी समस्या से कैसे संबंधित है - क्योंकि यह गतिशील रूप से उत्पन्न प्रपत्र फ़ील्ड और नाम नहीं दिखाता है?
Oddman

7
यह एक पूर्ण समाधान है (या वर्कअराउंड) और कोणीय टीम द्वारा सुझाए गए दृष्टिकोण ( docs.angularjs.org/api/ng.directive:form से ): "चूंकि आप गतिशील रूप से इंटरएक्शन का उपयोग करके इनपुट तत्वों के नाम विशेषता को उत्पन्न नहीं कर सकते हैं, आप एक ngForm निर्देश में दोहराया इनपुट के प्रत्येक सेट लपेटो और इन बाहरी रूप तत्व में घोंसला है। " प्रत्येक नेस्टेड फॉर्म का अपना दायरा होता है जो इसे काम करने की अनुमति देता है।
नोरेमैक

2
यह उदाहरण और सुझाव अभी भी गतिशील "नाम" को संबोधित नहीं करता है। ऐसा लगता है कि वे आपको गतिशील रूप से 'क्लोन' फ़ील्ड के सेट को घोंसला बनाने की अनुमति देना चाहते हैं, लेकिन प्रत्येक फ़ील्ड का अंतर्निहित नाम स्थिर होना चाहिए।
थिनिस

2
@thinice हाँ यह मदद करता है। इस समाधान के साथ नाम को गतिशील होने की आवश्यकता नहीं है। यह आप की तरह कुछ भी हो सकता है (जैसे "फू")। मुद्दा यह है कि बच्चे के रूप में इसका स्वयं का दायरा है, इसलिए सत्यापन अभिव्यक्तियाँ इनरफ़ॉर्म.फ़ू। $ त्रुटि आदि को संदर्भित कर सकती हैं। एनजी-मॉडल तब जो कुछ भी आप इसे चाहते हैं, उसे मूल दायरे में (संभवतः गतिशील रूप से) इंगित कर सकते हैं।
जेड रिचर्ड्स

@thinice - Wintamute सही है। डायनामिक नामों की कोई आवश्यकता नहीं है, क्योंकि आप सीधे फॉर्म जमा नहीं कर रहे हैं। इरादा कुछ मॉडल को बदलने का है, फिर अजाक्स के माध्यम से पोस्ट। गतिशील नाम उस बिंदु पर आपके द्वारा कुछ भी नहीं करने जा रहे हैं। यदि आप वास्तव में HTML फॉर्म सबमिट का उपयोग कर रहे हैं, तो आप कुछ अजीब / गलत कर रहे हैं, और आपको एक अलग दृष्टिकोण की आवश्यकता होगी।
बेन लेश

44

नेस्टेड ngForm का उपयोग करने से आप HTML टेम्पलेट के भीतर से विशिष्ट InputController का उपयोग कर सकते हैं। हालाँकि, यदि आप इसे किसी अन्य नियंत्रक से एक्सेस करना चाहते हैं तो यह मदद नहीं करता है।

जैसे

<script>
  function OuterController($scope) {
    $scope.inputName = 'dynamicName';

    $scope.doStuff = function() {
      console.log($scope.formName.dynamicName); // undefined
      console.log($scope.formName.staticName); // InputController
    }
  }
</script>

<div controller='OuterController'>
  <form name='myForm'>
    <input name='{{ inputName }}' />
    <input name='staticName' />
  </form>
  <a ng-click='doStuff()'>Click</a>
</div>

मैं इस निर्देश का उपयोग समस्या को हल करने में मदद करने के लिए करता हूं:

angular.module('test').directive('dynamicName', function($compile, $parse) {
  return {
    restrict: 'A',
    terminal: true,
    priority: 100000,
    link: function(scope, elem) {
      var name = $parse(elem.attr('dynamic-name'))(scope);
      // $interpolate() will support things like 'skill'+skill.id where parse will not
      elem.removeAttr('dynamic-name');
      elem.attr('name', name);
      $compile(elem)(scope);
    }
  };
});

अब आप डायनामिक नामों का उपयोग करते हैं जहाँ भी आवश्यकता होती है 'डायनामिक-नेम' विशेषता के बजाय 'नाम' विशेषता।

जैसे

<script>
  function OuterController($scope) {
    $scope.inputName = 'dynamicName';

    $scope.doStuff = function() {
      console.log($scope.formName.dynamicName); // InputController
      console.log($scope.formName.staticName); // InputController
    }
  }
</script>

<div controller='OuterController'>
  <form name='myForm'>
    <input dynamic-name='inputName' />
    <input name='staticName' />
  </form>
  <a ng-click='doStuff()'>Click</a>
</div>

1
मैंने इस समाधान का उपयोग $interpolateकरने के बजाय अपवाद के साथ $parseकिया, अधिक उपयोगी महसूस किया
TheRocketSurgeon

मैं देख रहा हूं कि आप टर्मिनेट करते हैं: सच। इसका क्या मतलब है? क्या मैं इस निर्देश का उपयोग रूपों के रूप में कर सकता हूँ, जैसे <form ng-repeat="item in items" dynamic-name="'item'+item.id"> ... <span ng-show="item{{item.id}}.$invalid">This form is invalid</span></form>?
felixfbecker

16

गितुब पर इस चर्चा के अनुसार, समस्या को AngularJS 1.3 में तय किया जाना चाहिए ।

इस बीच, यहां @caitp और @Thinkscape द्वारा बनाया गया एक अस्थायी समाधान है :

// Workaround for bug #1404
// https://github.com/angular/angular.js/issues/1404
// Source: http://plnkr.co/edit/hSMzWC?p=preview
app.config(['$provide', function($provide) {
    $provide.decorator('ngModelDirective', function($delegate) {
        var ngModel = $delegate[0], controller = ngModel.controller;
        ngModel.controller = ['$scope', '$element', '$attrs', '$injector', function(scope, element, attrs, $injector) {
            var $interpolate = $injector.get('$interpolate');
            attrs.$set('name', $interpolate(attrs.name || '')(scope));
            $injector.invoke(controller, this, {
                '$scope': scope,
                '$element': element,
                '$attrs': attrs
            });
        }];
        return $delegate;
    });
    $provide.decorator('formDirective', function($delegate) {
        var form = $delegate[0], controller = form.controller;
        form.controller = ['$scope', '$element', '$attrs', '$injector', function(scope, element, attrs, $injector) {
            var $interpolate = $injector.get('$interpolate');
            attrs.$set('name', $interpolate(attrs.name || attrs.ngForm || '')(scope));
            $injector.invoke(controller, this, {
                '$scope': scope,
                '$element': element,
                '$attrs': attrs
            });
        }];
        return $delegate;
    });
}]);

JSFiddle पर डेमो ।


1
1.2 एनजी पर अटके लोगों के लिए, यह आसानी से कम से कम 'हैकी' फिक्स है।
ग्रेनेड

14

@EnISeeK द्वारा एक अच्छा .... लेकिन मैं इसे अन्य निर्देशों के लिए अधिक सुरुचिपूर्ण और कम अप्रिय होने के लिए मिला:

.directive("dynamicName",[function(){
    return {
        restrict:"A",
        require: ['ngModel', '^form'],
        link:function(scope,element,attrs,ctrls){
            ctrls[0].$name = scope.$eval(attrs.dynamicName) || attrs.dynamicName;
            ctrls[1].$addControl(ctrls[0]);
        }
    };
}])

1
मैं केवल निम्नलिखित जोड़ूंगा। ctrls [0]। $ नाम = गुंजाइश। $ eval (attrs.dynamicName) || attrs.dynamicName;
GnrlBzik 19

7

EnlSeek समाधान पर बस थोड़ा सा सुधार

angular.module('test').directive('dynamicName', ["$parse", function($parse) {
 return {
    restrict: 'A',
    priority: 10000, 
    controller : ["$scope", "$element", "$attrs", 
           function($scope, $element, $attrs){
         var name = $parse($attrs.dynamicName)($scope);
         delete($attrs['dynamicName']);
         $element.removeAttr('data-dynamic-name');
         $element.removeAttr('dynamic-name');
          $attrs.$set("name", name);
    }]

  };
}]);

यहां प्लंकर का ट्रायल चल रहा हैयहाँ विस्तृत अन्वेषण है


+1, EnlSeek का निर्देश मेरे निर्देशन में एक अनंत लूप पैदा कर रहा था; मुझे इस जवाब के 'fx' टुकड़ों को निकालने के लिए काम करना था, हालांकि
जॉन

प्राथमिकता उन क्षेत्रों के सेट के साथ हस्तक्षेप कर सकती है जो एक ही नाम मानेंगे लेकिन एनजी-इफ है। उदाहरण: <इनपुट प्रकार = 'टेक्स्ट' डायनामिक-नाम = 'फू' एनजी-इफ = 'फील्ड.टाइप == "टेक्स्ट" /> <टेक्सएरिया डायनेमिक-नेम =' फू 'एनजी-इफ =' फील्ड.टाइप == "textarea"> </ textarea> 'प्राथमिकता: 10000' को हटाकर मेरे लिए समस्या हल हो गई और अभी भी सही ढंग से कार्य करने के लिए प्रकट होता है।
पतली

ngIf की प्राथमिकता 600 है। इस निर्देश के लिए 600 से कम प्राथमिकता दें, इसे ngIf के साथ मिलकर काम करना चाहिए।
जेसन झांग

यदि कोई प्राथमिकता निर्धारित नहीं है (डिफ़ॉल्ट 0), तो यह ngModel (प्राथमिकता 0) के साथ काम कर सकता है यदि यह निर्देश ngModel से पहले मूल्यांकन किया गया हो। आप इसे प्राथमिकता देना चाहते हैं ताकि यह हमेशा हो इससे पहले कि ngModel संकलित / लिंक हो।
जेसन झांग

5

मैं इस तरह गतिशील रूप से बनाए गए नेस्ट -फॉर्म की अनुमति देने के लिए, @Kitp और @Thinkscape समाधान को थोड़ा विस्तारित करता हूं :

<div ng-controller="ctrl">
    <ng-form name="form">
        <input type="text" ng-model="static" name="static"/>

        <div ng-repeat="df in dynamicForms">
            <ng-form name="form{{df.id}}">
                <input type="text" ng-model="df.sub" name="sub"/>
                <div>Dirty: <span ng-bind="form{{df.id}}.$dirty"></span></div>
            </ng-form>
        </div>

        <div><button ng-click="consoleLog()">Console Log</button></div>
        <div>Dirty: <span ng-bind="form.$dirty"></span></div>
    </ng-form>      
</div>

यहाँ JSFiddle पर मेरा डेमो है ।


4

मैंने बेन लेश के समाधान का इस्तेमाल किया और यह मेरे लिए अच्छा है। लेकिन एक समस्या जिसका मुझे सामना करना पड़ा, वह यह कि जब मैंने निर्देश का उपयोग कर रहा था तो ng-formसभी फॉर्म स्टेट्स जैसे उदाहरण form.$valid, form.$errorआदि का उपयोग करते हुए एक आंतरिक रूप जोड़ दिया ng-submit

तो अगर मैं उदाहरण के लिए यह था:

<form novalidate ng-submit="saveRecord()" name="outerForm">
    <!--parts of the outer form-->
    <ng-form name="inner-form">
      <input name="someInput">
    </ng-form>
    <button type="submit">Submit</button>
</form>

और मेरे नियंत्रक में:

$scope.saveRecord = function() {
    outerForm.$valid // this is undefined
}

इसलिए मुझे उस फॉर्म को जमा करने के लिए एक नियमित क्लिक ईवेंट का उपयोग करके वापस जाना पड़ा जिस स्थिति में फॉर्म ऑब्जेक्ट को पास करना आवश्यक है:

<form novalidate name="outerForm">  <!--remove the ng-submit directive-->
    <!--parts of the outer form-->
    <ng-form name="inner-form">
      <input name="someInput">
    </ng-form>
    <button type="submit" ng-click="saveRecord(outerForm)">Submit</button>
</form>

और संशोधित नियंत्रक विधि:

$scope.saveRecord = function(outerForm) {
    outerForm.$valid // this works
}

मुझे यकीन नहीं है कि ऐसा क्यों है लेकिन उम्मीद है कि यह किसी की मदद करता है।


3

यह मुद्दा कोणीय 1.3+ में तय किया गया है। आप जो करने की कोशिश कर रहे हैं, उसके लिए यह सही वाक्यविन्यास है:

login[input.name].$invalid

0

अगर हम नीचे दिए गए इनपुट की तरह डायनामिक नाम सेट करते हैं

<input name="{{dynamicInputName}}" />

फिर हमने नीचे कोड की तरह गतिशील नाम के लिए सेट सत्यापन का उपयोग किया है।

<div ng-messages="login.dynamicInputName.$error">
   <div ng-message="required">
   </div>
</div>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.