Angularjs: 'sözdizimi olarak denetleyici' ve $ watch


153

controller asSözdizimi kullanılırken mülk değişikliğine nasıl abone olunur ?

controller('TestCtrl', function ($scope) {
  this.name = 'Max';
  this.changeName = function () {
    this.name = new Date();
  }
  // not working       
  $scope.$watch("name",function(value){
    console.log(value)
  });
});
<div ng-controller="TestCtrl as test">
  <input type="text" ng-model="test.name" />
  <a ng-click="test.changeName()" href="#">Change Name</a>
</div>  

buna ne dersin. $ watch ()? Bu geçerli: bu. $ İzle ('isim', ...)
Joao Polo

Yanıtlar:


160

Sadece ilgili bağlamı bağlayın.

$scope.$watch(angular.bind(this, function () {
  return this.name;
}), function (newVal) {
  console.log('Name changed to ' + newVal);
});

Örnek: http://jsbin.com/yinadoce/1/edit

GÜNCELLEME:

Bogdan Gersak'ın cevabı aslında eşdeğerdir, her iki cevap thisda doğru bağlamla bağlanmaya çalışır. Ancak cevabını daha temiz buldum.

Bunu söyledikten sonra, her şeyden önce, arkasındaki temel fikri anlamanız gerekir .

GÜNCELLEME 2:

ES6 kullananlar arrow functioniçin, doğru içerik OOTB ile bir işlev elde edersiniz.

$scope.$watch(() => this.name, function (newVal) {
  console.log('Name changed to ' + newVal);
});

Misal


9
Bu ve $ kapsamı karışmasını önlemek için $ scope olmadan kullanabilir miyiz?
Miron

4
Bildiğim kadarıyla hayır, ama gayet iyi. $scopesizin için bu tür yöntemleri sağlayan bir tür hizmettir.
Roy Miloh

Eğer olup olmadığını netleştirmek Can nameiçinde return this.name;denetleyicisi veya mülk "adı belirtir nameburada"?
Jannik Jochem

3
@Jannik, angular.bindsınırlı bağlama sahip bir işlev döndürür (arg # 1). Bizim durumumuzda, thisdenetleyicinin örneği olan işleve (arg # 2) bağlanırız , yani denetleyicinin örneğinin this.nameözelliği anlamına gelir name.
Roy Miloh

Sanırım bunun nasıl çalıştığını anladım. Ciltli fonksiyon çağrıldığında izlenen değeri değerlendirir, değil mi?
Jannik Jochem

138

Genellikle bunu yaparım:

controller('TestCtrl', function ($scope) {
    var self = this;

    this.name = 'Max';
    this.changeName = function () {
        this.name = new Date();
   }

   $scope.$watch(function () {
       return self.name;
   },function(value){
        console.log(value)
   });
});

3
Bu en iyi cevap olduğunu kabul ediyorum, ancak bu karışıklık büyük olasılıkla ilk argüman olarak bir işlevi geçmekte $scope.$watchve bu işlevi kapanıştan bir değer döndürmek için kullanmak olduğunu ekleyeceğim . Henüz bunun başka bir örneğiyle karşılaşmadım, ama işe yarıyor ve en iyisi. Aşağıdaki cevabı (yani $scope.$watch('test.name', function (value) {});) seçmememin nedeni, şablonumda veya ui.router'ın $ stateProvider'ında denetleyicimi adlandırdığımı sabit kodlamam gerekiyordu ve oradaki herhangi bir değişiklik yanlışlıkla izleyiciyi kıracaktı.
Morris Singer

Ayrıca, bu yanıt ve şu anda kabul edilen cevap (kullanan angular.bind) arasındaki tek önemli fark , kapanışa bağlanmak thisveya sadece başka bir referans eklemek isteyip istemediğinizdir this. Bunlar işlevsel olarak eşdeğerdir ve deneyimlerime göre, bu tür bir seçim genellikle öznel bir çağrıdır ve çok güçlü bir görüş meselesidir.
Morris Singer

1
ES6 ile ilgili güzel bir şey, doğru js kapsamını elde etmek için yukarıda belirtilen 2 geçici çözümü ortadan kaldırmak olacaktır . $scope.$watch( ()=> { return this.name' }, function(){} ) Şişman ok kurtarmak için
jusopi

1
ayrıca yapabilirsin() => this.name
coblr

Bu işi yapabilir $scope.$watchCollectionve oldVal, newValparamleri hala alabilir misin?
Kraken

23

Kullanabilirsiniz:

   $scope.$watch("test.name",function(value){
        console.log(value)
   });

Bu örnek ile JSFiddle çalışıyor .


25
Bu yaklaşımla ilgili sorun, JS'nin HTML'ye güvenmesi ve $ watch'un çalışması için denetleyiciyi her yerde aynı ada (bu durumda "test") bağlamaya zorlamasıdır. İnce hataları tanıtmak çok kolay olurdu.
jsdw

Her şeyin bir yönerge olduğu Angular 2 gibi Angular 1 yazıyorsanız, bu harika bir şekilde işe yarıyor. Object.observe şu anda inanılmaz olurdu.
Langdon

13

Başka bir cevapta açıklandığı gibi, "TestCtrl test olarak" dan "test" kullanmaya benzer şekilde, kapsamınıza "ben" atayabilirsiniz:

controller('TestCtrl', function($scope){
    var self = this;
    $scope.self = self;

    self.name = 'max';
    self.changeName = function(){
            self.name = new Date();
        }

    $scope.$watch("self.name",function(value){
            console.log(value)
        });
})

Bu şekilde, DOM'de belirtilen ada bağlı değilsiniz ("testCtrl as test") ve ayrıca bir işleve .bind (this) bağlamanız gerekmez.

... belirtilen orijinal html ile kullanım için:

<div ng-controller="TestCtrl as test">
    <input type="text" ng-model="test.name" />
    <a ng-click="test.changeName()" href="#">Change Name</a>
</div>

Sadece bir şey bilmek istiyorum, yani, $scopebir hizmet, bu yüzden eklersek $scope.self = this, o zaman başka bir denetleyicide aynısını yaparsak, Orada ne olacak?
Vivek Kumar

12

AngularJs 1.5, ControllerAs yapısı için varsayılan $ ctrl'yi destekler.

$scope.$watch("$ctrl.name", (value) => {
    console.log(value)
});

$ WatchGroup kullanırken benim için çalışmıyor, bu bilinen bir sınır mı? hakkında hiçbir şey bulamadığım için bu özelliğin bağlantısını paylaşabilir misiniz?
user1852503

@ user1852503 Bkz. docs.angularjs.org/guide/component Karşılaştırma tablosu Yönerge / Bileşen tanımı ve 'controllerAs' kaydını kontrol edin.
Niels Steenbeek

Şimdi anlıyorum. Cevabınız biraz yanıltıcı. $ ctrl tanımlayıcısı bir özellik olarak denetleyiciyle ilişkili değildir (örneğin $ endeksi örneğin bir ng tekrarında olduğu gibi), sadece bir bileşen içindeki denetleyicinin varsayılan adı olur (ve soru bir bileşen).
user1852503

@ user1852503 1) $ ctrl, Controller (Controller as) ile ilişkilidir 2) Soru, bileşenlerle ilgilidir, çünkü şu ifadelerden bahseder: "<div ng-controller =" TestCtrl as test ">". 3) Bu sayfadaki tüm cevaplar bir şekilde cevabımla aynı. 4) Dokümanlarla ilgili olarak $ watchGroup, $ ctrl.name kullanılırken sadece $ watch'a dayandığından iyi çalışmalıdır.
Niels Steenbeek

2

bir işlevi $ watch () işlevinin ilk argümanı olarak iletebilirsiniz:

 app.controller('TestCtrl', function ($scope) {
 this.name = 'Max';

// hmmm, a function
 $scope.$watch(function () {}, function (value){ console.log(value) });
 });

Bu, this.name referansımızı iade edebileceğimiz anlamına gelir:

app.controller('TestCtrl', function ($scope) {
    this.name = 'Max';

    // boom
    $scope.$watch(angular.bind(this, function () {
    return this.name; // `this` IS the `this` above!!
    }), function (value) {
      console.log(value);
    });
});

Denetleyici hakkında ilginç bir yazı okuyun Konu https://toddmotto.com/digging-into-angulars-controller-as-syntax/



0

ES6 sözdiziminde $ watch yazmak beklediğim kadar kolay değildi. İşte yapabilecekleriniz:

// Assuming
// controllerAs: "ctrl"
// or
// ng-controller="MyCtrl as ctrl"
export class MyCtrl {
  constructor ($scope) {
    'ngInject';
    this.foo = 10;
    // Option 1
    $scope.$watch('ctrl.foo', this.watchChanges());
    // Option 2
    $scope.$watch(() => this.foo, this.watchChanges());
  }

  watchChanges() {
    return (newValue, oldValue) => {
      console.log('new', newValue);
    }
  }
}

-1

NOT : Bu, Görünüm ve Denetleyici bir rotada veya bir yönerge tanımlama nesnesi aracılığıyla bağlandığında çalışmaz. Aşağıda gösterilenler yalnızca HTML'de "SomeCtrl olarak SomeController" olduğunda işe yarar. Tıpkı Mark V.'nin aşağıdaki yorumda belirttiği gibi ve tıpkı Bogdan'ın yaptığı gibi yapmanın daha iyi olduğunu söylediği gibi.

Ben kullanıyorum: var vm = this;kontrolörün başında "bu" kelimesini yolumdan almak için. Sonra vm.name = 'Max';ve saatte ben return vm.name. @Bogdan "kendini" kullandığı gibi "vm" kullanıyorum. Bu var, "vm" ya da "self" olsun, çünkü "this" kelimesi fonksiyonun içinde farklı bir bağlam üstlenir. (yani this.name döndürmek işe yaramaz) Ve evet, $ watch ulaşmak için güzel "kontrolör" çözüm olarak $ kapsam enjekte gerekir. Bkz. John Papa'nın Stil Kılavuzu: https://github.com/johnpapa/angularjs-styleguide#controllers

function SomeController($scope, $log) {
    var vm = this;
    vm.name = 'Max';

    $scope.$watch('vm.name', function(current, original) {
        $log.info('vm.name was %s', original);
        $log.info('vm.name is now %s', current);
    });
}

11
Bu, HTML'nizde "SomeController vm kadar" olduğu sürece çalışır. Yine de yanıltıcı: saat ifadesindeki "vm.name" nin "var vm = this;" ile ilgisi yoktur. $ Watch işlevini "controller as" ile kullanmanın tek güvenli yolu, Bogdan'ın yukarıda açıkladığı gibi bir işlevi ilk argüman olarak iletmektir.
Mark Visser

-1

Bunu $ scope (ve $ watch!) Olmadan şu şekilde yapabilirsiniz: En İyi 5 Hata - Saati kötüye kullanma

"Controller as" sözdizimini kullanıyorsanız, $ scope kullanmamak daha iyidir.

İşte benim kod JSFiddle . (Adı tutmak için bir hizmet kullanıyorum, aksi takdirde ES5 Object.defineProperty's set ve alma yöntemleri sonsuz çağrılara neden olur.

var app = angular.module('my-module', []);

app.factory('testService', function() {
    var name = 'Max';

    var getName = function() {
        return name;
    }

    var setName = function(val) {
        name = val;
    }

    return {getName:getName, setName:setName};
});

app.controller('TestCtrl', function (testService) {
    var vm = this;

    vm.changeName = function () {
        vm.name = new Date();
    }

    Object.defineProperty(this, "name", {
        enumerable: true,
        configurable: false,
        get: function() {
            return testService.getName();
        },
        set: function (val) {
            testService.setName(val);
            console.log(vm.name);
        }
    }); 
});

Keman çalışmaz ve bu bir nesne özelliğini gözlemlemez.
Rootical V.28

@RooticalV. Keman çalışıyor. (AngualrJS'yi çalıştırırken, yük tipini nowrap-head / nowrap-body
Binu

özür dilerim ama hala çözüm bulamadım çünkü çözüm çok insterersting
happyZZR1400

@happy Kütüphaneyi Açısal 1.4 olarak seçtiğinizden emin olun. (2.0'ın çalışıp çalışmayacağından emin değilim) ve türü Sarma yok olarak yükle'yi ve Çalıştır'a basın. İşe yaramalı.
Binu Jasim
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.