it-swarm.asia

تمرير النموذج إلى التوجيه

أرغب في تغليف حقول النموذج الخاصة بي في توجيه بحيث يمكنني ببساطة القيام بذلك:

<div ng-form='myForm'>
  <my-input name='Email' type='email' label='Email Address' placeholder="Enter email" ng-model='model.email' required='false'></my-input>

</div>

كيف يمكنني الوصول إلى myForm في التوجيه الخاص بي حتى أتمكن من إجراء عمليات التحقق من الصحة ، على سبيل المثال myForm.Email.$valid؟

71
Emad

للوصول إلى FormController في توجيه:

require: '^form',

بعد ذلك سوف تكون متاحة كوسيطة الرابعة لوظيفة الرابط الخاص بك:

link: function(scope, element, attrs, formCtrl) {
    console.log(formCtrl);
}

fiddle

قد تحتاج فقط إلى الوصول إلى NgModelController على الرغم من:

require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
     console.log(ngModelCtrl);
}

fiddle

إذا كنت بحاجة إلى الوصول إلى كليهما:

require: ['^form','ngModel'],
link: function(scope, element, attrs, ctrls) {
    console.log(ctrls);
}

fiddle

149
Mark Rajcok

هنا كامل مثال (تم تصميمه باستخدام Bootstrap 3.1)

يحتوي على نموذج يحتوي على العديد من المدخلات (الاسم والبريد الإلكتروني والعمر والبلد). الاسم والبريد الإلكتروني والعمر هي توجيهات. البلد مدخلات "منتظمة".

لكل إدخال يتم عرض رسالة مساعدة عندما لا يقوم المستخدم بإدخال قيمة صحيحة.

يحتوي النموذج على زر حفظ تم تعطيله إذا كان النموذج يحتوي على خطأ واحد على الأقل.

<!-- index.html -->
<body ng-controller="AppCtrl">
  <script>
    var app = angular.module('app', []);

    app.controller('AppCtrl', function($scope) {
      $scope.person = {};
    });
  </script>
  <script src="inputName.js"></script>
  <script src="InputNameCtrl.js"></script>
  <!-- ... -->

  <form name="myForm" class="form-horizontal" novalidate>
    <div class="form-group">
      <input-name ng-model='person.name' required></input-name>
    </div>

    <!-- ... -->

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-4">
        <button class="btn btn-primary" ng-disabled="myForm.$invalid">
          <span class="glyphicon glyphicon-cloud-upload"></span> Save
        </button>
      </div>
    </div>
  </form>

  Person: <pre>{{person | json}}</pre>
  Form $error: <pre>{{myForm.$error | json}}</pre>
  <p>Is the form valid?: {{myForm.$valid}}</p>
  <p>Is name valid?: {{myForm.name.$valid}}</p>
</body>

// inputName.js
app.directive('inputName', function() {
  return {
    restrict: 'E',
    templateUrl: 'input-name.html',
    replace: false,
    controller: 'InputNameCtrl',
    require: ['^form', 'ngModel'],

    // See Isolating the Scope of a Directive http://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive
    scope: {},

    link: function(scope, element, attrs, ctrls) {
      scope.form = ctrls[0];
      var ngModel = ctrls[1];

      if (attrs.required !== undefined) {
        // If attribute required exists
        // ng-required takes a boolean
        scope.required = true;
      }

      scope.$watch('name', function() {
        ngModel.$setViewValue(scope.name);
      });
    }
  };
});

// inputNameCtrl
app.controller('InputNameCtrl', ['$scope', function($scope) {
}]);

 AngularJS form with directives 

32
tanguy_k

تحرير 2: سأترك إجابتي ، حيث قد يكون ذلك مفيدًا لأسباب أخرى ، لكن الإجابة الأخرى من Mark Rajcok هي ما أردت فعله أصلاً ، لكني فشلت في العمل. يبدو أن وحدة التحكم الأصل هنا ستكون form ، وليس ngForm.


يمكنك تمريرها باستخدام سمة في التوجيه الخاص بك ، على الرغم من أن ذلك سيصبح مطولًا إلى حد ما.

مثال

إليك العمل ، jsFiddle المبسطة .

الشفرة

HTML:

<div ng-form="myForm">
    <my-input form="myForm"></my-input>
</div>

الأجزاء الأساسية للتوجيه:

app.directive('myInput', function() {
    return {
        scope: {
            form: '='
        },
        link: function(scope, element, attrs) {
            console.log(scope.form);
        }
    };
});

ماذا يحدث

لقد طلبنا Angular ربط قيمة النطاق المسماة في سمة form بنطاقنا المعزول ، وذلك باستخدام '='.

يؤدي القيام بذلك بهذه الطريقة إلى فصل النموذج الفعلي عن توجيه الإدخال.

ملاحظة: حاولت استخدام require: "^ngForm" ، لكن توجيه ngForm لا يحدد وحدة تحكم ، ولا يمكن استخدامه بهذه الطريقة (وهو أمر سيء للغاية).


كل ما يقال ، أعتقد أن هذه طريقة مطلقة وفوضوي للتعامل مع هذا. قد يكون من الأفضل لك إضافة توجيه جديد إلى عنصر النموذج ، واستخدام require للوصول إلى هذا العنصر. سأرى إذا كان بإمكاني وضع شيء معًا.

تحرير: باستخدام توجيه الوالدين

حسنًا ، إليك أفضل ما يمكنني معرفته باستخدام توجيه الوالدين ، وسأشرح أكثر في الثانية:

العمل jsFiddle باستخدام توجيه الوالدين

HTML:

<div ng-app="myApp">
    <div ng-form="theForm">
        <my-form form="theForm">
            <my-input></my-input>
        </my-form>
    </div>
</div>

شبيبة (جزئي):

app.directive('myForm', function() {
    return {
        restrict: 'E',
        scope: {
            form: '='
        },
        controller: ['$scope', function($scope) {
            this.getForm = function() {
                return $scope.form;
            }
        }]
    }
});

app.directive('myInput', function() {
    return {
        require: '^myForm',
        link: function(scope, element, attrs, myForm) {
            console.log(myForm.getForm());
        }
    };
});

هذا يخزن النموذج في نطاق التوجيه الأصل (myForm) ، ويسمح للتوجيهات الفرعية بالوصول إليه من خلال طلب النموذج الأصل (require: '^myForm') ، والوصول إلى وحدة تحكم التوجيه في وظيفة الارتباط (myForm.getForm()).

فوائد:

  • ما عليك سوى تحديد النموذج في مكان واحد
  • يمكنك استخدام وحدة التحكم الرئيسية لإدخال رمز عام

السلبيات:

  • تحتاج إلى عقدة إضافية
  • تحتاج إلى وضع اسم النموذج مرتين

ما أفضل

كنت أحاول الحصول عليه للعمل باستخدام سمة في عنصر النموذج . إذا نجح هذا ، فلن يلزمك سوى إضافة التوجيه إلى نفس العنصر مثل ngForm.

ومع ذلك ، كنت أحصل على بعض السلوكيات الغريبة مع النطاق ، حيث سيكون المتغير myFormName مرئيًا في $scope ، ولكن سيكون undefined عندما حاولت الوصول إليه. هذا واحد قد حيرة لي.

17
OverZealous

بدءًا من AngularJS 1.5.0 ، يوجد حل أكثر نظافة لهذا (على عكس استخدام link مباشرة). إذا كنت ترغب في الوصول إلى FormController للنموذج في وحدة تحكم توجيه المكون الفرعي ، فيمكنك ببساطة صفعة السمة require على التوجيه ، مثل ذلك:

return {
  restrict : 'EA',
  require : {
    form : '^'
  },
  controller : MyDirectiveController,
  controllerAs : 'vm',
  bindToController : true,
  ...
};

بعد ذلك ، ستتمكن من الوصول إليه في القالب الخاص بك أو في وحدة التحكم في التوجيه كما تفعل مع أي متغير نطاق آخر ، {على سبيل المثال:

function MyDirectiveController() {
  var vm = this;
  console.log('Is the form valid? - %s', vm.form.$valid);
}

لاحظ أنه لكي يعمل هذا ، يجب أيضًا تعيين سمة bindToController: true في التوجيه الخاص بك. راجع الوثائق للحصول على $compile و هذا السؤال لمزيد من المعلومات.

الأجزاء ذات الصلة من الوثائق:

require

طلب توجيه آخر وإدخال وحدة التحكم فيه كوسيطة رابعة لوظيفة الربط. يمكن أن تكون الخاصية المطلوبة سلسلة ، صفيف أو كائن:

إذا كانت الخاصية المطلوبة هي {كائن و bindToController صادقة ، فإن وحدات التحكم المطلوبة تكون مرتبطة بوحدة التحكم باستخدام مفاتيح الخاصية المطلوبة. إذا كان اسم وحدة التحكم المطلوبة هو نفس الاسم المحلي (المفتاح) ، فيمكن حذف الاسم. على سبيل المثال ، {parentDir: '^parentDir'} مكافئ لـ {parentDir: '^'}.

7
Priidu Neemre

جعل العمل الخاص بك "ما أفضل" كمان! لسبب ما ، يمكنك مشاهدة سلسلة "$ scope.ngForm" في console.log ، لكن تسجيلها مباشرة لم ينجح ، مما أدى إلى عدم تحديده. ومع ذلك ، يمكنك الحصول عليه إذا قمت بتمرير سمات إلى وظيفة وحدة التحكم.

app.directive('myForm', function() {
return {
    restrict: 'A',
    controller: ['$scope','$element','$attrs', function($scope,$element,$attrs) {
        this.getForm = function() {
            return $scope[$attrs['ngForm']];
        }
    }]
}
});

http://jsfiddle.net/vZ6MD/20/

2
LobotomyKid