사용자 지정 지시문 내에서 평가 된 특성을 얻는 방법


363

사용자 지정 지시문에서 평가 된 속성 을 얻으려고하는데 올바른 방법을 찾을 수 없습니다.

정교한 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);
    }
});

내가 무엇을 놓치고 있습니까?


지시문에 대한 이해를 돕기 위해 아래 링크를 따라갈 수 있습니다. undefinednull.com/2014/02/11/…
Prasanna Sasne

답변:


573

참고 : 더 나은 솔루션을 찾으면이 답변을 업데이트합니다. 또한 관련이 유지되는 한 나중에 참조 할 수 있도록 이전 답변을 유지합니다. 최신의 최고의 답변이 우선입니다.

더 나은 답변 :

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 .

"여전히 OK"답변 :

이 답변은 받아 들였지만 몇 가지 문제가 있으므로 더 나은 답변으로 업데이트하겠습니다. 분명히 $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>​​​​​​​​

여기서 주목해야 할 것은 값 문자열을 설정하려면 따옴표로 묶어야한다는 것입니다. (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.$rootScope.Scope#$eval

결과를 반환하는 현재 범위에서 식을 실행합니다. 식의 모든 예외가 전파됩니다 (포착되지 않음). 각도 표현을 평가할 때 유용합니다.


답장을 보내 주셔서 감사하지만 해결책은 아닙니다. 코드로 바이올린을 업데이트했습니다. jsfiddle.net/neuTA/3
Shlomi Schwartz

Chrome에서 scope. $ parse를 사용하려고 할 때이 오류가 발생합니다. Object # <Object>에는 '$ parse'메서드가 없습니다. $ parse 서비스를 삽입하면 function ($ parse) {return function (scope ...-다음을 시도하십시오 : "value ="+ $ parse (attr.value)-그것은 저에게 효과가없는 것 같습니다 중.
마크 Rajcok

@ 마크 당신이 맞아, 이상한 바이올린 예제 ( jsfiddle.net/neuTA/4 ) 에서 작동 하지만 내가 가지고있는 코드는 아닙니다 ... 각도 버전?
Shlomi Schwartz

2
"더 나은 답변"섹션 $scope.text에서 연결 기능에서 정의되지 않습니다. 답변이 현재 표현 된 방식으로, 정의되지 않은 것처럼 들립니다. 보간 된 값을 비동기 적으로 보려면 $ observe () (또는 실제로는 $ watch ()가 여기에서도 작동합니다)를 사용해야합니다. 내 대답을 참조 또한 stackoverflow.com/questions/14876112/...
마크 Rajcok

1
에서 "아직 OK"응답 보인다 $parse서비스를 주입 한 후 사용되지 않습니다. 뭔가 빠졌습니까?
superjos

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.


이것이 당신이 찾은 유일한 해결책입니까?
Shlomi Schwartz

4
예, 지시문 페이지에서이 방법을 권장하므로이 방법을 사용하십시오.
Mark Rajcok

7
+1, 이것은 최선의 답은이 지침에 범위를 강요하지 않기 때문에 IMO이며, 또한과 속성 변경을 포함 $ 관찰
BiAiB

4

다른 답변은 매우 정확하고 귀중합니다. 그러나 때로는 업데이트가 필요하지 않고 격리 범위를 망칠 필요없이 지시문 인스턴스화에서 일반 오래된 구문 분석 값을 얻는 것이 간단합니다. 예를 들어, 지시문에 선언적 페이로드를 배열 또는 해시 객체로 형식으로 제공하는 것이 편리 할 수 ​​있습니다.

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

이 경우 추적을 자르고 멋진 기본을 사용할 수 있습니다 angular.$eval(attr.attrName).

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

바이올린 .


오래된 각도 버전을 사용했는지 여부를 모르지만 모든 코드 샘플이 유효하지 않은 javascript (my-directive-name =) 또는 유효하지 않은 각도 (angular. $ eval이 존재하지 않음)이므로 -1
BiAiB

음 ...이 게시물이 1 년이 넘었다는 점을 고려할 때 무언가가 더 이상 사용되지 않는 경우 전혀 놀라운 일이 아닙니다. 그러나 10 초 동안 Google을 검색하면 여기에 SO를 포함하여 $ eval에 대한 많은 자료가 있습니다 . 그리고 당신이 인용하는 다른 예는 Javascript가 아닌 HTML에서의 호출입니다.
XML

$ scope. $ eval (attr.val)은 각도 1.4에서 작동합니다. 지시문 링크 함수에 $ scope를 주입해야합니다.
Martin Connell

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

                }

            });

        }
    };
});


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


내 결과는 다음과 같습니다

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

}

변경 사항이 적용되지 않도록 dom로드 후 지시문 호출 때문에 $ timeout 사용

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.