Özel bir yönergede değerlendirilmiş öznitelikler nasıl alınır?


363

Özel yönergemden değerlendirilmiş bir özellik almaya çalışıyorum , ancak bunu yapmanın doğru yolunu bulamıyorum.

Oluşturduğum bu jsFiddle ayrıntılı için.

<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);
    }
});

Neyi kaçırıyorum?


Direktifleri daha iyi anlamak için aşağıdaki bağlantıyı takip edebilirsiniz. undefinednull.com/2014/02/11/…
Prasanna Sasne

Yanıtlar:


573

Uyarı: Daha iyi çözümler bulduğum için bu cevabı güncelliyorum. Ayrıca, eski yanıtları ilgili oldukları sürece ileride başvurmak üzere saklarım. En son ve en iyi cevap önce gelir.

Daha iyi cevap:

Angularjs'deki direktifler çok güçlüdür, ancak arkasında hangi süreçlerin yattığını anlamak zaman alır.

Direktifler oluştururken, angularjs , ana kapsama bazı bağlamalar ile yalıtılmış bir kapsam oluşturmanıza izin verir . Bu bağlamaları tarafından belirtilen öznitelik DOM içinde eleman eklemek ve nasıl tanımladığına kapsam tesisle yönergesi tanım nesnesi .

Kapsamda tanımlayabileceğiniz 3 tür bağlama seçeneği vardır ve bunları öneklerle ilgili öznitelik olarak yazarsınız.

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>

Bu durumda, yönerge kapsamında (bağlantı fonksiyonunda veya denetleyicide olsun), bu özelliklere şu şekilde erişebiliriz:

/* 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 .

"Hala iyi" Cevap:

Bu yanıt kabul edildiğinden, ancak bazı sorunları olduğundan, daha iyi bir cevapla güncelleyeceğim. Görünüşe göre, $parsemevcut kapsamın özelliklerinde yer almayan bir hizmettir, yani sadece açısal ifadeler alır ve kapsama ulaşamaz. {{, }}Bizim direktifler bunları erişmeye çalıştığınızda angularjs hangi aracı başlatılması sırasında ifadeleri derlenmektedir postlinkyöntemle, zaten derlenmektedir. ( {{1+1}}Olduğu 2zaten yönergede).

Bu şekilde kullanmak istersiniz:

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>​​​​​​​​

Burada dikkat etmeniz gereken bir şey, eğer değer dizesini ayarlamak istiyorsanız, onu tırnak içine almanız gerektiğidir. (Bkz. 3. giriş)

İşte oynamak için keman: http://jsfiddle.net/neuTA/6/

Eski Cevap:

Benim gibi yanıltılabilen insanlar için bunu kaldırmıyorum, kullanmanın $evaldoğru yolun mükemmel olduğunu, ancak $parsefarklı bir davranışa sahip olduğunu unutmayın, muhtemelen çoğu durumda kullanmak için buna ihtiyacınız olmayacaktır.

Bunu yapmanın yolu bir kez daha kullanmaktır scope.$eval. Sadece açısal ifadeyi derlemekle kalmaz, aynı zamanda geçerli kapsamın özelliklerine de erişebilir.

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

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

function MyCtrl($scope) {

}​

Eksik olan neydi $eval.

http://docs.angularjs.org/api/ng.$rootScope.Scope#$eval

Sonucu döndüren geçerli kapsamdaki ifadeyi yürütür. İfadedeki istisnalar yayılır (yakalanmaz). Bu, açısal ifadeleri değerlendirirken faydalıdır.


Cevabınız için teşekkürler, ancak bu çözüm değil. Kodunuzu kodunuzla güncelledim. jsfiddle.net/neuTA/3
Shlomi Schwartz

Chrome'da, kapsamı kullanmaya çalışırken bu hatayı alıyorum. $ Parse: Object # <Object> '$ parse' yöntemine sahip değil. $ Parse service - function ($ parse) {return function (scope ... -) enjekte edersem, şunu deneyin: "value =" + $ parse (attr.value) - bu benim için işe yaramıyor ya.
Mark Rajcok

@Mark haklısın, garip bir keman örneğinde ( jsfiddle.net/neuTA/4 ) çalışıyor ama kodda değil ... açısal sürümleri?
Shlomi Schwartz

2
"Daha iyi cevap" bölümünde, $scope.textbağlantı fonksiyonunda tanımsız olacaktır. Cevabın şu anda ifade edildiği şekilde, tanımsız olmayacak gibi görünüyor. Enterpolasyonlu değeri eşzamansız olarak görmek için $ observe () (veya $ watch () burada da çalışır) kullanmanız gerekir. Cevabımı görün ve ayrıca stackoverflow.com/questions/14876112/…
Mark Rajcok

1
In "Yine Tamam" Yanıt görünüyor $parsehizmet enjekte ve sonra hiçbir zaman kullanılmaz. Bir şey mi kaçırıyorum?
superjos

83

Yalıtılmış bir kapsam kullanmayan bir direktifte enterpolasyon yapılması gereken bir özellik değeri için, ör.

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

Öznitelikler yöntemini kullanın $observe:

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

Gönderen direktif sayfasında

enterpolasyonlu nitelikleri gözlemleme: Enterpolasyon $observeiçeren özelliklerin değer değişikliklerini (örn. src="{{bar}}") gözlemlemek için kullanın . Bu sadece çok verimli olmakla kalmaz, aynı zamanda gerçek değeri kolayca elde etmenin tek yoludur çünkü bağlantı aşamasında enterpolasyon henüz değerlendirilmemiştir ve bu nedenle değer şu anda ayarlanmıştır undefined.

Özellik değeri yalnızca bir sabitse, ör.

<input my-directive value="123">

değer bir sayı veya boole ise $ eval kullanabilirsiniz ve doğru türü istiyorsanız:

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

Özellik değeri bir dize sabitiyse veya değerin direktifinizde dize türü olmasını istiyorsanız, değere doğrudan erişebilirsiniz:

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

Ancak sizin durumunuzda, enterpolasyonlu değerleri ve sabitleri desteklemek istediğiniz için kullanın $observe.


bulduğun tek çözüm bu muydu?
Shlomi Schwartz

4
Evet, ve direktif sayfası bu yaklaşımı önerdiğinden, bunu böyle yapardım.
Mark Rajcok

7
+1, bu IMO'nun en iyi yanıtıdır, çünkü direktif üzerinde bir kapsamı zorlamamaktadır ve aynı zamanda $ gözlemlemek ile nitelik değişikliklerini de kapsamaktadır
BiAiB

4

Buradaki diğer cevaplar çok doğru ve değerlidir. Ancak bazen sadece basit istersiniz: direktif örneğinde, güncellemelere ihtiyaç duymadan ve izolat kapsamıyla uğraşmadan düz bir eski ayrıştırılmış değer elde etmek. Örneğin, yönerge formunda bir dizi veya karma nesne olarak bildirici bir yük sağlamak yararlı olabilir:

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

Bu durumda, kovalamaca kesebilir ve sadece güzel bir temel kullanabilirsiniz angular.$eval(attr.attrName).

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

Çalışma keman .


Eski bir açısal sürüm kullandıysanız ya da değil mi bilmiyorum, ama tüm kod örnekleri geçersiz javascript (my-directive-name =) ya da geçersiz açısal (açısal. $ Eval mevcut değil), yani -1
BiAiB

Ummm ... bu yazının bir yıldan daha eski olduğu göz önüne alındığında, o zamandan beri bir şeyin kullanımdan kaldırılması şaşırtıcı olmazdı. Bununla birlikte, 10 saniyelik bir Google araması, tam olarak SO'da dahil olmak üzere $ eval'de size bol miktarda malzeme bulur . Ve alıntı yaptığınız diğer örnek Javascript değil, HTML'deki bir çağrıdır.
XML

$ scope. $ eval (attr.val) açısal olarak çalışır 1.4. Direktif bağlantı fonksiyonuna $ kapsamının enjekte edilmesini gerektirir.
Martin Connell

4

Aradığım aynı çözüm için Angularjs directive with ng-Model.
İşte sorunu çözen kod.

    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);
                    }

                }

            });

        }
    };
});


HTML DOM

<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">


Sonucum:

92108-2223

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) {

}

$ Timeout kullanın çünkü dom yüklendikten sonra direktif çağrısı yapın, böylece değişiklikleriniz geçerli değil

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.