AngularJS 1.5+ 구성 요소는 감시자를 지원하지 않습니다. 해결 방법은 무엇입니까?
사용자 지정 지시문을 새로운 구성 요소 아키텍처 로 업그레이드했습니다 . 구성 요소가 감시자를 지원하지 않는다는 것을 읽었습니다. 이 올바른지? 그렇다면 물체의 변화를 어떻게 감지합니까? 기본 예를 들어 myBox
게임에 바인딩이있는 자식 구성 요소 게임이있는 사용자 지정 구성 요소 가 있습니다. 게임 구성 요소 내에 변경 게임이있는 경우 myBox에 경고 메시지를 표시하려면 어떻게해야합니까? rxJS 방법이 있다는 것을 이해합니다. 순전히 각도로 수행 할 수 있습니까? 내 JSFiddle
자바 스크립트
var app = angular.module('myApp', []);
app.controller('mainCtrl', function($scope) {
$scope.name = "Tony Danza";
});
app.component("myBox", {
bindings: {},
controller: function($element) {
var myBox = this;
myBox.game = 'World Of warcraft';
//IF myBox.game changes, show alert message 'NAME CHANGE'
},
controllerAs: 'myBox',
templateUrl: "/template",
transclude: true
})
app.component("game", {
bindings: {game:'='},
controller: function($element) {
var game = this;
},
controllerAs: 'game',
templateUrl: "/template2"
})
HTML
<div ng-app="myApp" ng-controller="mainCtrl">
<script type="text/ng-template" id="/template">
<div style='width:40%;border:2px solid black;background-color:yellow'>
Your Favourite game is: {{myBox.game}}
<game game='myBox.game'></game>
</div>
</script>
<script type="text/ng-template" id="/template2">
<div>
</br>
Change Game
<textarea ng-model='game.game'></textarea>
</div>
</script>
Hi {{name}}
<my-box>
</my-box>
</div><!--end app-->
감시자 없이 구성 요소 작성
이 답변은 감시자 를 사용하지 않고 AngularJS 1.5 구성 요소를 작성하는 데 사용하는 5 가지 기술을 간략하게 설명 합니다.
- 지시어 사용
ng-change
- 사용
$onChanges
수명주기 후크를 - 사용
$doCheck
수명주기 후크를 - require 와의 상호 구성 요소 통신
- RxJS 를 사용하여 서비스에서 값 푸시
ng-change
지시어 사용
AngularJs2를 준비 할 때 watch를 사용하지 않고 obj 상태 변경을 관찰 할 수있는 대체 메서드는 무엇입니까?
ng-change
지시문을 사용하여 입력 변경에 반응 할 수 있습니다 .
<textarea ng-model='game.game'
ng-change="game.textChange(game.game)">
</textarea>
이벤트를 상위 구성 요소로 전파하려면 이벤트 처리기를 하위 구성 요소의 속성으로 추가해야합니다.
<game game='myBox.game' game-change='myBox.gameChange($value)'></game>
JS
app.component("game", {
bindings: {game:'=',
gameChange: '&'},
controller: function() {
var game = this;
game.textChange = function (value) {
game.gameChange({$value: value});
});
},
controllerAs: 'game',
templateUrl: "/template2"
});
그리고 부모 구성 요소에서 :
myBox.gameChange = function(newValue) {
console.log(newValue);
});
이것은 앞으로 선호되는 방법입니다. 사용하는 AngularJS 전략은 $watch
폴링 전략이기 때문에 확장 가능하지 않습니다. $watch
청취자 수가 약 2000 명에 이르면 UI가 느려집니다. 각도 2의 전략 프레임 워크 반응성과 피할 배치하는 것입니다 $watch
에를 $scope
.
사용 $onChanges
수명주기 후크를
으로 버전 1.5.3 , AngularJS와 추가 된 $onChanges
받는 라이프 사이클 후크 $compile
서비스를.
문서에서 :
컨트롤러는 수명주기 후크 역할을하는 다음 메서드를 제공 할 수 있습니다.
- $ onChanges (changesObj)-단방향 (
<
) 또는 보간 (@
) 바인딩이 업데이트 될 때마다 호출 됩니다. 는changesObj
그 키 변경된 결합 속성의 이름은 해쉬이고, 값은 형태의 목적이다{ currentValue: ..., previousValue: ... }
. 이 후크를 사용하여 바인딩 된 값 복제와 같은 구성 요소 내에서 업데이트를 트리거하여 외부 값의 우발적 변형을 방지합니다.
$onChanges
후크와 성분으로 외부 변화에 반응하는 데 사용되는 <
일방향 바인딩. 이 ng-change
지시문은 바인딩을 사용 ng-model
하여 구성 요소 외부의 컨트롤러 에서 변경 사항을 전파하는 데 사용됩니다 &
.
사용 $doCheck
수명주기 후크를
으로 버전 1.5.8 , AngularJS와 추가 된 $doCheck
받는 라이프 사이클 후크 $compile
서비스를.
문서에서 :
컨트롤러는 수명주기 후크 역할을하는 다음 메서드를 제공 할 수 있습니다.
$doCheck()
-다이제스트 사이클의 매 턴마다 호출됩니다. 변경 사항을 감지하고 조치를 취할 수있는 기회를 제공합니다. 감지 한 변경 사항에 대한 응답으로 취하려는 조치는이 후크에서 호출되어야합니다. 이것을 구현해도를$onChanges
호출 할 때 영향을주지 않습니다 . 예를 들어,이 후크는 깊은 동등성 검사를 수행하거나 Angular의 변경 탐지기에 의해 감지되지 않아 트리거되지 않는 Date 객체를 확인하려는 경우 유용 할 수 있습니다$onChanges
. 이 후크는 인수없이 호출됩니다. 변경 사항을 감지하는 경우 현재 값과 비교하기 위해 이전 값을 저장해야합니다.
구성 요소 간 통신 require
지시문은 서로 통신 할 수 있도록 다른 지시문의 컨트롤러를 요구할 수 있습니다 . 이는 require 속성에 대한 개체 매핑을 제공하여 구성 요소에서 수행 할 수 있습니다 . 개체 키는 필수 컨트롤러 (개체 값)가 필요한 구성 요소의 컨트롤러에 바인딩되는 속성 이름을 지정합니다.
app.component('myPane', {
transclude: true,
require: {
tabsCtrl: '^myTabs'
},
bindings: {
title: '@'
},
controller: function() {
this.$onInit = function() {
this.tabsCtrl.addPane(this);
console.log(this);
};
},
templateUrl: 'my-pane.html'
});
자세한 내용은 AngularJS 개발자 가이드-Intercomponent Communicatation을 참조하십시오.
RxJS 를 사용하여 서비스에서 값 푸시
예를 들어 상태를 유지하는 서비스가있는 상황에서는 어떻습니까? 해당 서비스에 대한 변경 사항을 푸시하고 페이지의 다른 임의 구성 요소가 그러한 변경 사항을 인식하는 방법은 무엇입니까? 최근이 문제를 해결하는 데 어려움을 겪고 있습니다.
Angular 용 RxJS Extensions 로 서비스를 구축합니다 .
<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);
app.factory("DataService", function(rx) {
var subject = new rx.Subject();
var data = "Initial";
return {
set: function set(d){
data = d;
subject.onNext(d);
},
get: function get() {
return data;
},
subscribe: function (o) {
return subject.subscribe(o);
}
};
});
그런 다음 변경 사항을 구독하십시오.
app.controller('displayCtrl', function(DataService) {
var $ctrl = this;
$ctrl.data = DataService.get();
var subscription = DataService.subscribe(function onNext(d) {
$ctrl.data = d;
});
this.$onDestroy = function() {
subscription.dispose();
};
});
클라이언트는를 사용하여 변경 사항을 구독 할 수 DataService.subscribe
있고 생산자는 DataService.set
.
$watch
개체는 개체 내에서 사용할 수
$scope
있으므로 $scope
컨트롤러 팩토리 함수 내부 에 추가
한 다음 변수 위에 감시자를 배치해야합니다.
$scope.$watch(function(){
return myBox.game;
}, function(newVal){
alert('Value changed to '+ newVal)
});
참고 : 당신이 변환 한 알
directive
에component
의 의존성을 제거하기 위해,$scope
당신은 한 걸음 더 가까이 Angular2을 얻을 수 있도록합니다. 그러나이 경우에는 제거되지 않은 것 같습니다.
최신 정보
기본적으로 각도 1.5는 .component
두 가지 다른 기능을 차별화하는 방법을 추가했습니다 . 마찬가지로 component
.stands는 추가 특정 behaviby을 수행하기 selector
로하는 경우, directive
스탠드 DOM에 특정 동작을 추가 할 수 있습니다. Directive는 .directive
DDO (Directive Definition Object)의 래퍼 방법 일뿐 입니다. 당신이 볼 수있는 것은 각도 컴파일 된 DOM을 얻을 수있는 방법 link/compile
을 사용 .component
하는 동안 제거 기능 이 있다는 것입니다.
Angular 컴포넌트 라이프 사이클 후크의 $onChanges
/ $doCheck
라이프 사이클 후크를 사용하십시오 . Angular 1.5.3+ 버전 이후에 사용할 수 있습니다.
$ onChanges (changesObj) -바인딩이 업데이트 될 때마다 호출됩니다. changesObj는 키가 바인딩 된 속성의 이름 인 해시입니다.
$ doCheck () -바인딩이 변경 될 때 다이제스트 사이클의 각 턴에 호출됩니다. 변경 사항을 감지하고 조치를 취할 수있는 기회를 제공합니다.
구성 요소 내부에서 동일한 기능을 사용하면 코드가 Angular 2로 이동할 수 있도록 호환됩니다.
내 솔루션에 관심이있는 사람이라면 누구나 RXJS Observables에 의지하게되는데, Angular 2에 도달했을 때 사용해야하는 것은 다음과 같습니다. 여기에는 구성 요소 간의 통신을위한 작업 바이올린이 있으며, 무엇을 볼 것인지에 대한 더 많은 제어를 제공합니다.
class BoxCtrl {
constructor(msgService) {
this.msgService = msgService
this.msg = ''
this.subscription = msgService.subscribe((obj) => {
console.log('Subscribed')
this.msg = obj
})
}
unsubscribe() {
console.log('Unsubscribed')
msgService.usubscribe(this.subscription)
}
}
var app = angular
.module('app', ['ngMaterial'])
.controller('MainCtrl', ($scope, msgService) => {
$scope.name = "Observer App Example";
$scope.msg = 'Message';
$scope.broadcast = function() {
msgService.broadcast($scope.msg);
}
})
.component("box", {
bindings: {},
controller: 'BoxCtrl',
template: `Listener: </br>
<strong>{{$ctrl.msg}}</strong></br>
<md-button ng-click='$ctrl.unsubscribe()' class='md-warn'>Unsubscribe A</md-button>`
})
.factory('msgService', ['$http', function($http) {
var subject$ = new Rx.ReplaySubject();
return {
subscribe: function(subscription) {
return subject$.subscribe(subscription);
},
usubscribe: function(subscription) {
subscription.dispose();
},
broadcast: function(msg) {
console.log('success');
subject$.onNext(msg);
}
}
}])
ng-change
허용되는 답변과 함께 권장되는 앵글 1.5 구성 요소와 함께 사용에 관한 작은 알림 .
In case you need to watch a component that ng-model
and ng-change
do not work, you can pass the parameters as:
Markup in which component is used:
<my-component on-change="$ctrl.doSth()"
field-value="$ctrl.valueToWatch">
</my-component>
Component js:
angular
.module('myComponent')
.component('myComponent', {
bindings: {
onChange: '&',
fieldValue: '='
}
});
Component markup:
<select ng-model="$ctrl.fieldValue"
ng-change="$ctrl.onChange()">
</select>
Available in IE11, MutationObserver https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver. You need to inject $element service into controller which semi-breaks DOM/controller separation, but I feel that this is a fundamental exception (ie. flaw) in angularjs. Since hide/show is async, we need on-show callback, that angularjs & angular-bootstrap-tab do not provide. It also requires that u know which specific DOM element u want to observe. I used following code for angularjs controller to trigger Highcharts chart reflow on-show.
const myObserver = new MutationObserver(function (mutations) {
const isVisible = $element.is(':visible') // Requires jquery
if (!_.isEqual(isVisible, $element._prevIsVisible)) { // Lodash
if (isVisible) {
$scope.$broadcast('onReflowChart')
}
$element._prevIsVisible = isVisible
}
})
myObserver.observe($element[0], {
attributes: true,
attributeFilter: ['class']
})
Really Nice accepted answer, but I might add that you can use also the power of events ( a bit like in Qt signal / slots if you will ).
An event is broadcast : $rootScope.$broadcast("clickRow", rowId)
by any parent ( or even children controller ). Then in your controller you can handle the event like this :
$scope.$on("clickRow", function(event, data){
// do a refresh of the view with data == rowId
});
You can also add some logging on that like this ( taken from here : https://stackoverflow.com/a/34903433/3147071 )
var withLogEvent = true; // set to false to avoid events logs
app.config(function($provide) {
if (withLogEvent)
{
$provide.decorator("$rootScope", function($delegate) {
var Scope = $delegate.constructor;
var origBroadcast = Scope.prototype.$broadcast;
var origEmit = Scope.prototype.$emit;
Scope.prototype.$broadcast = function() {
console.log("$broadcast was called on $scope " + this.$id + " with arguments:",
arguments);
return origBroadcast.apply(this, arguments);
};
Scope.prototype.$emit = function() {
console.log("$emit was called on $scope " + this.$id + " with arguments:",
arguments);
return origEmit.apply(this, arguments);
};
return $delegate;
});
}
});
I'm late. But it can help to another people.
app.component("headerComponent", {
templateUrl: "templates/header/view.html",
controller: ["$rootScope", function ($rootScope) {
let $ctrl = this;
$rootScope.$watch(() => {
return $ctrl.val;
}, function (newVal, oldVal) {
// do something
});
}]
});
'developer tip' 카테고리의 다른 글
Twitter Bootstrap 3의 절반 열 (0) | 2020.10.16 |
---|---|
X 분마다 cronjob을 실행하는 방법은 무엇입니까? (0) | 2020.10.16 |
확산 구문을 사용하는 ES6의 전체 복사 (0) | 2020.10.16 |
Python에서 객체 목록 검색 (0) | 2020.10.15 |
후행 슬래시가없는 django URL은 리디렉션되지 않습니다. (0) | 2020.10.15 |