Angular JS'de kontrolörler arasında veri mi aktarıyorsunuz?


243

Ürünlerimi gösteren temel bir denetleyicim var,

App.controller('ProductCtrl',function($scope,$productFactory){
     $productFactory.get().success(function(data){
           $scope.products = data;
     });
});

Bana göre bu ürünleri bir listede gösteriyorum

<ul>
    <li ng-repeat="product as products">
        {{product.name}}
    </li>
</ul

Ne yapmaya çalışıyorum biri ürün adını tıkladığında, ben bu ürünün eklendi sepeti adlı başka bir görünüm var.

 <ul class="cart">
      <li>
          //click one added here
      </li>
      <li>
          //click two added here
      </li>
 </ul>

Bu yüzden şüphe ediyorum ki, bu tıklanan ürünleri ilk kontrol cihazından ikinciye nasıl geçiririm? Ben sepeti de bir denetleyici olması gerektiğini varsaydı.

Ben direktif kullanarak click olayı ele. Ayrıca yukarıdaki işlevselliği elde etmek için hizmet kullanmak gerektiğini hissediyorum nasıl anlayamıyorum? çünkü sepeti önceden tanımlanmış olacak eklenmiş ürün sayısı, kullanıcının hangi sayfaya bağlı olduğuna bağlı olarak 5/10 olabilir. Bu yüzden bu jenerik tutmak istiyorum.

Güncelleme:

Yayınlamak için bir hizmet oluşturdum ve ikinci denetleyicide alıyorum. Şimdi sorgu nasıl dom güncellemek olduğunu? Listeyi bırakacağım ürün oldukça kodlanmış olduğundan.


Yanıtlar:


322

Açıklamasından, bir hizmet kullanıyor olmanız gerekir. Http://egghead.io/lessons/angularjs-sharing-data-between-controllers ve AngularJS Hizmetinin Denetleyiciler Arasında Veri Aktarımı'na göz atınBazı örnekleri görmek için .

Ürün hizmetinizi (fabrika olarak) şu şekilde tanımlayabilirsiniz:

app.factory('productService', function() {
  var productList = [];

  var addProduct = function(newObj) {
      productList.push(newObj);
  };

  var getProducts = function(){
      return productList;
  };

  return {
    addProduct: addProduct,
    getProducts: getProducts
  };

});

Bağımlılık hizmeti her iki denetleyiciye de enjekte eder.

Gözlerinde farklı ProductController, diziye seçilen nesne ekler bazı eylem tanımlayın:

app.controller('ProductController', function($scope, productService) {
    $scope.callToAddToProductList = function(currObj){
        productService.addProduct(currObj);
    };
});

Ürününüzde CartController, ürünleri hizmetten alın:

app.controller('CartController', function($scope, productService) {
    $scope.products = productService.getProducts();
});

3
GetProducts () çağrıldığında Cart denetleyicisi bir kez güncellenir mi? Yoksa her yeni ürün eklendiğinde?
kishanio

1
Otomatik olarak güncellenmesini istiyorsanız, yayını Maxim Shoustin'in cevabından ekleyebilir ve CartCtrl'in kapsamını güncellemek için $ on işlevi içinde getProducts () öğesini çağırabilirsiniz.
Chalise

2
@krillgar Tamamen haklısın, bu başlangıçta gözden kaçtı. Cevabı çalışan bir çözümü yansıtacak şekilde düzenledim.
Chalise

1
@DeveshM Evet, önerdiğiniz gibi yapın. Yöntemleri yalnızca verileri bellekte tutmayacak ve daha kalıcı olacak şekilde genişletmeyi düşünebilirsiniz ( $httpörneğin, çağrı yoluyla sunucuya kaydedin ).
Chalise

1
Örneğin 2 productController ve 2 el arabam varsa ne olur? Her ikisi de öğe eklenecek mi? Bu durumda bunu nasıl çözersiniz?
atoth

67

Tıklanan bu ürünler ilk kontrolörden ikinciye nasıl geçer?

Tıklandığında yayını çağıran yöntemi çağırabilirsiniz :

$rootScope.$broadcast('SOME_TAG', 'your value');

ve ikinci denetleyici bu etiketi şu şekilde dinleyecektir:

$scope.$on('SOME_TAG', function(response) {
      // ....
})

Hizmetlere $ kapsam enjekte edemediğimiz için, tek bir $ kapsamı gibi bir şey yoktur.

Ama enjekte edebiliriz $rootScope. Dolayısıyla, değeri Hizmete depolarsanız $rootScope.$broadcast('SOME_TAG', 'your value');, Hizmet gövdesinde çalışabilirsiniz . (Hizmetler hakkında @Charx açıklamasına bakın)

app.service('productService',  function($rootScope) {/*....*/}

Lütfen $ broadcast , $ emit hakkında iyi makaleyi kontrol edin


1
Evet bu fabrika kullanıyorum cazibe gibi çalışır? Sıkıştığım son bir şey var, ürünü her tıklattığımda yeni denetleyicide veri alıyorum. Şimdi DOM'da nasıl güncelleyebilirim? Zaten sınırları olan 5 kodlu listesini söyleyebileceğim için, her ürün onların içine
girmeli

1
@KT - Hiç cevap aldınız mı? Bu açık bir soru gibi görünüyor ama cevabı hiçbir yerde bulamıyorum. Bir denetleyicinin bazı değerleri değiştirmesini istiyorum. Bu uygulama değeri değiştiğinde, diğer dinleme denetleyicilerinin kendilerini gerektiği şekilde güncelleştirmeleri gerekir. Bulamıyorum.
raddevus

2
@ gün ışığının cevabını q. sahip olduğunuz denetleyici yapısına dayanır: paralel veya alt-ebeveyn. $rootScope.$broadcastparalel yapıya sahip tüm denetleyicileri aynı düzeyde bilgilendirir.
Maxim Shoustin

@ MS Cevabınız için teşekkürler. $ Watch kullanarak bunu yapmanın bir yolu var mı? BTW, Mine paralel kontrolörler ve yönteminizi kullanarak işe koyuldum. Benim için, $ watch ($ rootScope'a bile) eklemeye çalıştığımda, 2. kontrol cihazındaki $ watch ile ilişkili yöntem yalnızca ilk kez (2. kontrol cihazının başlatılması) tetiklenir. Teşekkürler.
raddevus

1
$watchdeğer $rootScopeseviyede mevcutsa kullanabiliriz . Aksi takdirde, yalnızca yayın diğer denetleyicilere bildirimde bulunabilir. FYI, kodunuzda başka bir programcı görürse broadcast- mantık ne yapmaya çalıştığınız açıktır - "broadcast olayı". Her neyse, benim exp. kullanmak rootscopeiçin iyi bir uygulama değil watch. "Yalnızca 1. kez ateş" hakkında: bu örneğe bir göz atın: plnkr.co/edit/5zqkj7iYloeHYkzK1Prt?p=pr eski ve yeni değerleriniz olduğunu görün. Her seferinde eskisine eşit olmayan yeni bir değer elde ettiğinizden emin olun
Maxim Shoustin

24

$ RootScope kullanarak Servis oluşturmadan çözüm:

Özellikleri Uygulama Denetleyicileri arasında paylaşmak için Angular $ rootScope'u kullanabilirsiniz. Bu, verileri paylaşmak için başka bir seçenektir ve insanların bunu bilmesini sağlar.

Bazı işlevleri Denetleyiciler arasında paylaşmanın tercih edilen yolu Hizmetler'dir, $ rootscope kullanabileceğiniz global bir özelliği okumak veya değiştirmek için kullanılır.

var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = true;
}]);

app.controller('Ctrl2', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = false;
}]);

Şablonda $ rootScope kullanma ($ root ile Access özellikleri):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>

27
$rootScopemümkün olduğunca kaçınılmalıdır.
Shaz

1
@Shaz nedenini açıklayabilir misin?
Mirko

5
@Mirko Global durumdan mümkün olduğunca kaçınmaya çalışmalısınız çünkü herkes bunu değiştirebilir - program durumunuzu tahmin edilemez hale getirir.
Umut Yedi

4
$ rootScope global bir kapsama sahiptir, bu nedenle yerel global değişkenler gibi bunları da dikkatli bir şekilde kullanmamız gerekir. Herhangi bir denetleyici değerlerini değiştirirse, genel kapsam için değiştirilir.
Sanjeev

1
Hizmetler ve Fabrikaların her ikisi de Singleton'dur, ancak Denetleyicinize herhangi bir servis enjekte etmeyi veya vermemeyi seçebilirsiniz. Ancak tüm çocuk kapsamı anaçtan türetilir ve prototip zinciri takip eder. Bu nedenle, kapsamınızdaki bir özelliğe erişmeye çalışırsanız ve mevcut değilse, zinciri arar. İsterseniz rootscope özelliğini değiştirebilme olasılığınız vardır.
Sanjeev

16

Bunu iki yöntemle yapabilirsiniz.

  1. Kullanarak $rootscope , ama bunu tavsiye etmiyorum. En $rootScopeüst kapsamdır. Bir uygulama, bir uygulamanın $rootScopetüm bileşenleri arasında paylaşılacak yalnızca bir tanesine sahip olabilir. Dolayısıyla küresel bir değişken gibi davranır.

  2. Hizmetleri kullanma. Bunu iki denetleyici arasında bir hizmet paylaşarak yapabilirsiniz. Hizmet kodu şöyle görünebilir:

    app.service('shareDataService', function() {
        var myList = [];
    
        var addList = function(newObj) {
            myList.push(newObj);
        }
    
        var getList = function(){
            return myList;
        }
    
        return {
            addList: addList,
            getList: getList
        };
    });

    Kemanımı burada görebilirsiniz .


ve 3. bir seçenek olarak, sadece listeye eklemek için etkinlik gönderebilirsiniz
DanteTheSmith

KULLANICI SAYFAYI YENİLİRSE NE YAPAR? SONRA getProducts () SİZE HİÇBİR ŞEY
VERECEKTİR

2
@shreedharbhat Soru, sayfa yeniden yüklemelerinde sürekli verilerin sorulmasını istemiyor.
Jack Vial

9

Verileri denetleyiciler arasında paylaşmanın daha basit bir yolu, iç içe veri yapıları kullanmaktır. Örneğin,

$scope.customer = {};

kullanabiliriz

$scope.data = { customer: {} };

dataBiz onun alanlarını üzerine yazabilirsiniz böylece mülkiyet diğer kontrolörler erişimi tutarak üst kapsamdan miras olacaktır.


1
Denetleyiciler kapsam özelliklerini üst Denetleyicilerden kendi kapsamına devralır. Temiz! basitlik güzel yapar
Carlos R Balebona

çalıştıramaz. ikinci denetleyicide $ scope.data kullanıyorum ve tanımsız.
Bart Calixto

Sanırım iç içe kontrolörlerden bahsediyor. Bana da pek faydası yok.
Norbert Norbertson

8
angular.module('testAppControllers', [])
    .controller('ctrlOne', function ($scope) {
        $scope.$broadcast('test');
    })
    .controller('ctrlTwo', function ($scope) {
        $scope.$on('test', function() {
        });
    });

niether kullanıyor
Leathan

5

verileri oturumda saklayabilir ve program dışında herhangi bir yerde kullanabiliriz.

$window.sessionStorage.setItem("Mydata",data);

Başka yer

$scope.data = $window.sessionStorage.getItem("Mydata");

4

Burada cevapları gördüm ve denetleyiciler arasında veri paylaşımı sorusunu cevaplıyor, ancak bir denetleyicinin verilerin değiştirildiği (yayın kullanmadan) hakkında diğerini bilgilendirmesini istiyorsam ne yapmalıyım? KOLAY! Sadece ünlü ziyaretçi kalıbını kullanarak:

myApp.service('myService', function() {

    var visitors = [];

    var registerVisitor = function (visitor) {
        visitors.push(visitor);
    }

    var notifyAll = function() {
        for (var index = 0; index < visitors.length; ++index)
            visitors[index].visit();
    }

    var myData = ["some", "list", "of", "data"];

    var setData = function (newData) {
        myData = newData;
        notifyAll();
    }

    var getData = function () {
        return myData;
    }

    return {
        registerVisitor: registerVisitor,
        setData: setData,
        getData: getData
    };
}

myApp.controller('firstController', ['$scope', 'myService',
    function firstController($scope, myService) {

        var setData = function (data) {
            myService.setData(data);
        }

    }
]);

myApp.controller('secondController', ['$scope', 'myService',
    function secondController($scope, myService) {

        myService.registerVisitor(this);

        this.visit = function () {
            $scope.data = myService.getData();
        }

        $scope.data = myService.getData();
    }
]);

Bu basit şekilde, bir denetleyici başka bir denetleyiciyi bazı verilerin güncellendiğini güncelleyebilir.


2
Gözlemci düzeni ( en.wikipedia.org/wiki/Observer_pattern ) burada daha alakalı olmaz mıydı? Ziyaretçi kalıbı başka bir şeydir ... en.wikipedia.org/wiki/Visitor_pattern
Ant Kutschera

3

Rota yolunun deseni arasında paylaşılan kapsamı kontrol eden bir fabrika oluşturdum, böylece kullanıcılar aynı rota üst yolunda gezinirken paylaşılan verileri koruyabilirsiniz.

.controller('CadastroController', ['$scope', 'RouteSharedScope',
    function($scope, routeSharedScope) {
      var customerScope = routeSharedScope.scopeFor('/Customer');
      //var indexScope = routeSharedScope.scopeFor('/');
    }
 ])

Dolayısıyla, kullanıcı '/ Destek' gibi başka bir yol yoluna giderse, '/ Müşteri' yolu için paylaşılan veriler otomatik olarak imha edilir. Ancak, bunun yerine kullanıcı '/ Customer / 1' veya '/ Customer / list' gibi 'alt' yollara giderse kapsam yok olmaz.

Burada bir örnek görebilirsiniz: http://plnkr.co/edit/OL8of9


3

1

using $localStorage

app.controller('ProductController', function($scope, $localStorage) {
    $scope.setSelectedProduct = function(selectedObj){
        $localStorage.selectedObj= selectedObj;
    };
});

app.controller('CartController', function($scope,$localStorage) { 
    $scope.selectedProducts = $localStorage.selectedObj;
    $localStorage.$reset();//to remove
});

2

Tıklandığında yayını çağıran yöntemi arayabilirsiniz:

$rootScope.$broadcast('SOME_TAG', 'your value');

and the second controller will listen on this tag like:
$scope.$on('SOME_TAG', function(response) {
      // ....
})

3

using $rootScope:

4

window.sessionStorage.setItem("Mydata",data);
$scope.data = $window.sessionStorage.getItem("Mydata");

5

Açısal hizmet kullanarak tek yönlü:

var app = angular.module("home", []);

app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});

app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});

app.factory('ser1', function(){
return {o: ''};
});

2
cevabınıza biraz daha açıklama yapın.
Gerhard Barnard

2

Modülünüzde bir fabrika oluşturun ve denetleyiciye fabrika referansı ekleyin ve değişkenlerini denetleyicide kullanın ve şimdi istediğiniz yere referans ekleyerek başka bir denetleyicideki verilerin değerini alın


2

Kimseye yardım edip etmeyeceğini bilmiyorum, ama Charx (teşekkürler!) Cevabına göre basit önbellek hizmeti oluşturdum. Kullanmak, remiks yapmak ve paylaşmaktan çekinmeyin:

angular.service('cache', function() {
    var _cache, _store, _get, _set, _clear;
    _cache = {};

    _store = function(data) {
        angular.merge(_cache, data);
    };

    _set = function(data) {
        _cache = angular.extend({}, data);
    };

    _get = function(key) {
        if(key == null) {
            return _cache;
        } else {
            return _cache[key];
        }
    };

    _clear = function() {
        _cache = {};
    };

    return {
        get: _get,
        set: _set,
        store: _store,
        clear: _clear
    };
});

2

Açısal hizmet kullanarak tek yönlü:

var app = angular.module("home", []);

app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});


app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});

app.factory('ser1', function(){
return {o: ''};
});



<div ng-app='home'>

<div ng-controller='one'>
  Type in text: 
  <input type='text' ng-model="inputText.o"/>
</div>
<br />

<div ng-controller='two'>
  Type in text:
  <input type='text' ng-model="inputTextTwo.o"/>
</div>

</div>

https://jsfiddle.net/1w64222q/



1

$ Broadcast kullanarak @Maxim tarafından önerilen çözümü geliştirmek için veri gönderme değişmez

$rootScope.$broadcast('SOME_TAG', 'my variable');

ama verileri dinlemek için

$scope.$on('SOME_TAG', function(event, args) {
    console.log("My variable is", args);// args is value of your variable
})

1

Bunu yapmanın üç yolu var,

a) bir hizmet kullanmak

b) Kontrolör kapsamları arasında ebeveyn / çocuk ilişkisine bağlı olarak yararlanma.

c) Açısal 2.0'da "As" anahtar sözcüğü, verileri bir denetleyiciden diğerine geçirecektir.

Örnekle ilgili daha fazla bilgi için lütfen aşağıdaki bağlantıyı kontrol edin:

http://www.tutespace.com/2016/03/angular-js.html


0
var custApp = angular.module("custApp", [])
.controller('FirstController', FirstController)
.controller('SecondController',SecondController)
.service('sharedData', SharedData);

FirstController.$inject = ['sharedData'];
function FirstController(sharedData) {
this.data = sharedData.data;
}

SecondController.$inject['sharedData'];
function SecondController(sharedData) {
this.data = sharedData.data;
}

function SharedData() {
this.data = {
    value: 'default Value'
}
}

İlk Kontrolör

<div ng-controller="FirstController as vm">
<input type=text ng-model="vm.data.value" />
</div>

İkinci Kontrolör

 <div ng-controller="SecondController as vm">
    Second Controller<br>
    {{vm.data.value}}
</div>

-1

Bence

en iyi yol

$ localStorage kullanmaktır. (Her zaman çalışır)

app.controller('ProductController', function($scope, $localStorage) {
    $scope.setSelectedProduct = function(selectedObj){
        $localStorage.selectedObj= selectedObj;
    };
});

CardController'ınız

app.controller('CartController', function($scope,$localStorage) { 
    $scope.selectedProducts = $localStorage.selectedObj;
    $localStorage.$reset();//to remove
});

Ayrıca ekleyebilirsiniz

if($localStorage.selectedObj){
    $scope.selectedProducts = $localStorage.selectedObj;
}else{
    //redirect to select product using $location.url('/select-product')
}
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.