365

カスタム ディレクティブから評価済みの属性を取得しようとしていますが、正しい方法が見つかりません。

詳しく説明するために、この jsFiddleを作成しました。

<div ng-controller="MyCtrl">
    <input my-directive value="123">
    <input my-directive value="{{1+1}}">
</div>

myApp.directive('myDirective', function () {
    return function (scope, element, attr) {
        element.val("value = "+attr.value);
    }
});

私は何が欠けていますか?

4

5 に答える 5

578

注意:より良い解決策を見つけたら、この回答を更新します。また、それらが関連している限り、将来の参考のために古い回答を保持します。最新のベスト アンサーが最初に表示されます。

より良い答え:

angularjs のディレクティブは非常に強力ですが、背後にあるプロセスを理解するには時間がかかります。

ディレクティブを作成している間、angularjs を使用すると、親スコープへのバインディングを使用して分離スコープを作成できます。これらのバインディングは、DOM で要素にアタッチする属性と、ディレクティブ定義オブジェクトでスコーププロパティを定義する方法によって指定されます。

スコープで定義できるバインド オプションには 3 つのタイプがあり、それらをプレフィックス関連の属性として記述します。

angular.module("myApp", []).directive("myDirective", function () {
    return {
        restrict: "A",
        scope: {
            text: "@myText",
            twoWayBind: "=myTwoWayBind",
            oneWayBind: "&myOneWayBind"
        }
    };
}).controller("myController", function ($scope) {
    $scope.foo = {name: "Umur"};
    $scope.bar = "qwe";
});

HTML

<div ng-controller="myController">
    <div my-directive my-text="hello {{ bar }}" my-two-way-bind="foo" my-one-way-bind="bar">
    </div>
</div>

その場合、ディレクティブのスコープで (関数またはコントローラーのリンクに関係なく)、次のようにこれらのプロパティにアクセスできます。

/* Directive scope */

in: $scope.text
out: "hello qwe"
// this would automatically update the changes of value in digest
// this is always string as dom attributes values are always strings

in: $scope.twoWayBind
out: {name:"Umur"}
// this would automatically update the changes of value in digest
// changes in this will be reflected in parent scope

// in directive's scope
in: $scope.twoWayBind.name = "John"

//in parent scope
in: $scope.foo.name
out: "John"


in: $scope.oneWayBind() // notice the function call, this binding is read only
out: "qwe"
// any changes here will not reflect in parent, as this only a getter .

「まだ大丈夫です」 答え:

この回答は受け入れられましたが、いくつかの問題があるため、より良いものに更新します。どうやら、$parse現在のスコープのプロパティにないサービスです。つまり、角度式のみを取り、スコープに到達できません。 {{}}式は angularjs の開始中にコンパイルされます。つまり、ディレクティブpostlinkメソッドでそれらにアクセスしようとすると、それらは既にコンパイルされています。(すでにディレクティブになっています){{1+1}}2

これはあなたが使いたい方法です:

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

myApp.directive('myDirective', function ($parse) {
    return function (scope, element, attr) {
        element.val("value=" + $parse(attr.myDirective)(scope));
    };
});

function MyCtrl($scope) {
    $scope.aaa = 3432;
}​

.

<div ng-controller="MyCtrl">
    <input my-directive="123">
    <input my-directive="1+1">
    <input my-directive="'1+1'">
    <input my-directive="aaa">
</div>​​​​​​​​

ここで注意すべきことの 1 つは、値の文字列を設定する場合は、引用符で囲む必要があるということです。(3 番目の入力を参照)

ここで遊ぶフィドルは次のとおりです:http://jsfiddle.net/neuTA/6/

古い答え:

私のように誤解される可能性のある人のためにこれを削除するつもりはありません。使用$evalは正しい方法で完全に問題ありませんが$parse、動作が異なります。ほとんどの場合、これを使用する必要はないでしょう。

それを行う方法は、もう一度、を使用することscope.$evalです。角度式をコンパイルするだけでなく、現在のスコープのプロパティにもアクセスできます。

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

myApp.directive('myDirective', function () {
    return function (scope, element, attr) {
        element.val("value = "+ scope.$eval(attr.value));
    }
});

function MyCtrl($scope) {
   
}​

あなたが欠けているのは$eval.

http://docs.angularjs.org/api/ng.$ro​​otScope.Scope#$eval

結果を返す現在のスコープで式を実行します。式内のすべての例外が伝搬されます (キャッチされません)。これは、角度式を評価するときに役立ちます。

于 2012-09-11T14:50:43.687 に答える
83

分離スコープを使用していないディレクティブで補間する必要がある属性値の場合、たとえば、

<input my-directive value="{{1+1}}">

属性のメソッドを使用します$observe:

myApp.directive('myDirective', function () {
  return function (scope, element, attr) {
    attr.$observe('value', function(actual_value) {
      element.val("value = "+ actual_value);
    })
 }
});

ディレクティブのページから、

$observe補間された属性の観察: 補間を含む属性 (例: ) の値の変化を観察するために使用しますsrc="{{bar}}"。これは非常に効率的であるだけでなく、実際の値を簡単に取得する唯一の方法でもあります。これは、リンク段階では補間がまだ評価されておらず、この時点で値が に設定されているためundefinedです。

属性値が単なる定数の場合、たとえば、

<input my-directive value="123">

値が数値またはブール値で、正しい型が必要な場合は$evalを使用できます。

return function (scope, element, attr) {
   var number = scope.$eval(attr.value);
   console.log(number, number + 1);
});

属性値が文字列定数の場合、またはディレクティブで値を文字列型にしたい場合は、直接アクセスできます。

return function (scope, element, attr) {
   var str = attr.value;
   console.log(str, str + " more");
});

ただし、あなたの場合、補間された値と定数をサポートしたいので、$observe.

于 2012-09-12T19:49:24.720 に答える
4

私が探していたのと同じ解決策のためにAngularjs directive with ng-Model
問題を解決するコードは次のとおりです。

    myApp.directive('zipcodeformatter', function () {
    return {
        restrict: 'A', // only activate on element attribute
        require: '?ngModel', // get a hold of NgModelController
        link: function (scope, element, attrs, ngModel) {

            scope.$watch(attrs.ngModel, function (v) {
                if (v) {
                    console.log('value changed, new value is: ' + v + ' ' + v.length);
                    if (v.length > 5) {
                        var newzip = v.replace("-", '');
                        var str = newzip.substring(0, 5) + '-' + newzip.substring(5, newzip.length);
                        element.val(str);

                    } else {
                        element.val(v);
                    }

                }

            });

        }
    };
});


HTMLDOM

<input maxlength="10" zipcodeformatter onkeypress="return isNumberKey(event)" placeholder="Zipcode" type="text" ng-readonly="!checked" name="zipcode" id="postal_code" class="form-control input-sm" ng-model="patient.shippingZipcode" required ng-required="true">


私の結果は次のとおりです。

92108-2223
于 2014-05-27T13:14:21.120 に答える
4

ここでの他の回答は非常に正しく、価値があります。しかし、単純にしたい場合もあります。ディレクティブのインスタンス化で、更新を必要とせず、isolate スコープをいじることなく、単純な古い解析済みの値を取得したい場合です。たとえば、次の形式の配列またはハッシュオブジェクトとして宣言型ペイロードをディレクティブに提供すると便利な場合があります。

my-directive-name="['string1', 'string2']"

その場合、本題に切り込んで、素敵な基本的なangular.$eval(attr.attrName).

element.val("value = "+angular.$eval(attr.value));

働くフィドル

于 2014-04-05T16:00:36.050 に答える
2
var myApp = angular.module('myApp',[]);

myApp .directive('myDirective', function ($timeout) {
    return function (scope, element, attr) {
        $timeout(function(){
            element.val("value = "+attr.value);
        });

    }
});

function MyCtrl($scope) {

}

dom のロード後にディレクティブが呼び出され、変更が適用されないため、$timeout を使用します

于 2015-09-02T07:54:45.027 に答える