Melewati data antara pengontrol di Angular JS?

243

Saya memiliki pengontrol dasar yang menampilkan produk saya,

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

Dalam pandangan saya, saya menampilkan produk ini dalam daftar

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

Apa yang saya coba lakukan adalah ketika seseorang mengklik nama produk, saya memiliki pandangan lain bernama keranjang tempat produk ini ditambahkan.

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

Jadi keraguan saya di sini adalah, bagaimana cara melewati produk yang diklik ini dari pengontrol pertama ke kedua? Saya berasumsi bahwa kereta harus menjadi pengontrol juga.

Saya menangani event klik menggunakan arahan. Saya juga merasa saya harus menggunakan layanan untuk mencapai fungsionalitas di atas hanya tidak tahu bagaimana caranya? karena keranjang akan ditentukan sebelumnya jumlah produk yang ditambahkan bisa 5/10 tergantung pada pengguna halaman mana. Jadi saya ingin menyimpan generik ini.

Memperbarui:

Saya membuat layanan untuk menyiarkan dan di controller kedua saya menerimanya. Sekarang pertanyaannya adalah bagaimana cara saya memperbarui dom? Karena daftar saya untuk menjatuhkan produk cukup hardcode.

Kishanio
sumber

Jawaban:

322

Dari uraian, sepertinya Anda harus menggunakan layanan. Lihat http://egghead.io/lessons/angularjs-sharing-data-between-controllers dan Layanan AngularJS Melewati Data Antar Pengendali untuk melihat beberapa contoh.

Anda dapat mendefinisikan layanan produk Anda (sebagai pabrik) sebagai berikut:

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

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

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

  return {
    addProduct: addProduct,
    getProducts: getProducts
  };

});

Ketergantungan memasukkan layanan ke kedua pengontrol.

Di Anda ProductController, tentukan beberapa tindakan yang menambahkan objek yang dipilih ke array:

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

Di Anda CartController, dapatkan produk dari layanan:

app.controller('CartController', function($scope, productService) {
    $scope.products = productService.getProducts();
});
Chalise
sumber
3
Pengontrol keranjang akan memperbarui sekali ketika getProducts () dipanggil? Atau setiap kali produk baru ditambahkan?
kishanio
1
Jika Anda ingin pembaruan secara otomatis, Anda dapat menambahkan siaran dari jawaban Maxim Shoustin dan memanggil getProducts () dalam fungsi $ on untuk memperbarui lingkup CartCtrl.
Chalise
2
@ krillgar Anda sepenuhnya benar, yang pada awalnya diabaikan. Saya telah mengedit jawaban untuk mencerminkan solusi yang berfungsi.
Chalise
1
@ EveshM Ya, lakukan seperti yang Anda sarankan. Anda mungkin ingin mempertimbangkan untuk memperluas metode sehingga tidak hanya menyimpan data dalam memori dan menjadi lebih persisten (simpan ke server melalui $httppanggilan, misalnya).
Chalise
1
Apa yang terjadi jika saya memiliki 2 productControllers dan 2 kereta misalnya? Keduanya akan memiliki elemen yang ditambahkan? Bagaimana Anda menyelesaikannya dalam kasus ini?
atoth
67

bagaimana cara melewati produk yang diklik ini dari pengontrol pertama ke kedua?

Pada klik Anda dapat memanggil metode yang meminta siaran :

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

dan controller kedua akan mendengarkan tag ini seperti:

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

Karena kami tidak dapat memasukkan $ scope ke dalam layanan, tidak ada yang seperti $ scope tunggal.

Tapi kita bisa menyuntikkan $rootScope. Jadi, jika Anda menyimpan nilai ke dalam Layanan, Anda dapat menjalankannya $rootScope.$broadcast('SOME_TAG', 'your value');di badan Layanan. (Lihat deskripsi @Charx tentang layanan)

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

Silakan periksa artikel bagus tentang $ broadcast , $ emit

Maxim Shoustin
sumber
1
Yup ini berfungsi seperti pesona yang saya gunakan pabrik? Hanya ada satu hal terakhir di mana saya terjebak saya mendapatkan data di controller baru setiap kali saya mengklik produk. Sekarang bagaimana saya memperbaruinya di DOM? Karena saya sudah memiliki katakanlah daftar 5 hardcoded dengan perbatasan sehingga setiap produk harus masuk ke dalamnya
kishanio
1
@KT - Apakah Anda pernah mendapat jawaban? Sepertinya ini pertanyaan yang jelas, tetapi saya tidak dapat menemukan jawabannya di mana pun. Saya ingin pengontrol mengubah beberapa nilai. Ketika nilai aplikasi berubah, maka pengontrol mendengarkan lainnya harus memperbarui dirinya sendiri seperlunya. Tidak dapat menemukannya
raddevus
2
@menyalakan jawaban pada q Anda. didasarkan pada struktur controller apa yang Anda miliki: parallel atau child-parent. $rootScope.$broadcastmemberitahukan semua pengontrol yang memiliki struktur paralel alias tingkat yang sama.
Maxim Shoustin
@ MS Terima kasih atas jawabannya. Apakah ada cara untuk melakukan ini menggunakan $ watch? BTW, Milik saya adalah pengontrol paralel dan saya membuatnya bekerja menggunakan metode Anda. Bagi saya, setiap kali saya mencoba untuk menambahkan $ watch (bahkan ke $ rootScope) metode yang terkait dengan $ watch di pengontrol ke-2 hanya akan mengaktifkan pertama kali (inisialisasi pengontrol ke-2). Terima kasih.
raddevus
1
kita dapat menggunakan $watchjika nilai ada pada $rootScopelevel. Kalau tidak, hanya siaran yang bisa memberi tahu pengontrol lain. FYI, jika programmer lain melihat kode Anda broadcast- logikanya jelas apa yang Anda coba lakukan - "siaran acara". Bagaimanapun, dari exp saya. prakteknya tidak baik untuk digunakan rootscopeuntuk watch. Tentang "fire 1st time only": lihat contoh ini: plnkr.co/edit/5zqkj7iYloeHYkzK1Prt?p=preview Anda memiliki nilai lama dan baru. pastikan bahwa setiap kali Anda mendapatkan nilai baru yang tidak sama dengan yang lama
Maxim Shoustin
24

Solusi tanpa membuat Layanan, menggunakan $ rootScope:

Untuk berbagi properti di Pengontrol aplikasi, Anda dapat menggunakan Angular $ rootScope. Ini adalah pilihan lain untuk berbagi data, menaruhnya agar orang tahu tentangnya.

Cara yang disukai untuk berbagi beberapa fungsionalitas di Pengontrol adalah Layanan, untuk membaca atau mengubah properti global yang dapat Anda gunakan $ rootscope.

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

Menggunakan $ rootScope dalam templat (Mengakses properti dengan $ root):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>
Sanjeev
sumber
27
$rootScopeharus dihindari sebisa mungkin.
Shaz
1
@ Shaz, bisakah Anda menjelaskan mengapa?
Mirko
5
@Mirko Anda harus berusaha menghindari keadaan global sebanyak yang Anda bisa karena siapa pun dapat mengubahnya - membuat keadaan program Anda tidak dapat diprediksi.
Umut Seven
4
$ rootScope memiliki cakupan global, jadi seperti variabel global asli, kita harus menggunakannya dengan hati-hati. Jika ada pengontrol yang mengubah nilainya, itu akan diubah untuk lingkup global.
Sanjeev
1
Layanan & Pabrik keduanya Singleton, tetapi Anda dapat memilih untuk menyuntikkan atau tidak layanan apa pun di Controller Anda. Tetapi semua ruang lingkup anak berasal dari rootscope dan mengikuti rantai prototipikal. Jadi, jika Anda mencoba mengakses properti pada ruang lingkup Anda dan tidak ada maka itu akan mencari rantai. Ada kemungkinan bahwa Anda yang tidak diinginkan dapat mengubah properti rootscope.
Sanjeev
16

Anda dapat melakukan ini dengan dua metode.

  1. Dengan menggunakan $rootscope, tapi saya tidak merekomendasikan ini. The $rootScopeadalah paling atas lingkup. Sebuah aplikasi hanya dapat memiliki satu $rootScopeyang akan dibagikan di antara semua komponen aplikasi. Karenanya ia bertindak seperti variabel global.

  2. Menggunakan layanan. Anda dapat melakukan ini dengan berbagi layanan antara dua pengontrol. Kode untuk layanan mungkin terlihat seperti ini:

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

    Anda bisa melihat biola saya di sini .

Nisham Mahsin
sumber
dan opsi ke-3, Anda dapat mengirim acara, hanya untuk menambah daftar
DanteTheSmith
BAGAIMANA JIKA PENGGUNA MEMBUAT HALAMAN? LALU getProducts () TIDAK AKAN MEMBERI ANDA! (Anda tidak dapat memberitahu semua pengguna untuk tidak menyegarkan, kan?)
shreedhar bhat
2
@shreedharbhat Pertanyaannya bukan tentang data yang ada di seluruh halaman yang dimuat ulang.
Jack Vial
9

Cara yang bahkan lebih sederhana untuk berbagi data antara pengontrol menggunakan struktur data bersarang. Alih-alih, misalnya

$scope.customer = {};

kita bisa menggunakan

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

The dataproperti akan diwarisi dari lingkup orangtua sehingga kita dapat menimpa bidang nya, menjaga akses dari kontroler lain.

Bartłomiej Zalewski
sumber
1
Controllers mewarisi properti lingkup dari Controllers induk ke lingkupnya sendiri. Bersih! kesederhanaan membuatnya cantik
Carlos R Balebona
tidak bisa membuatnya bekerja. pada controller kedua saya menggunakan $ scope.data dan itu tidak terdefinisi.
Bart Calixto
Dia berbicara tentang pengendali bersarang, saya pikir. Tidak banyak gunanya bagiku juga.
Norbert Norbertson
8
angular.module('testAppControllers', [])
    .controller('ctrlOne', function ($scope) {
        $scope.$broadcast('test');
    })
    .controller('ctrlTwo', function ($scope) {
        $scope.$on('test', function() {
        });
    });
Jijo Paulose
sumber
ia menggunakan niether
Leathan
5

kita dapat menyimpan data dalam sesi dan dapat menggunakannya di mana saja di luar program.

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

Tempat lain

$scope.data = $window.sessionStorage.getItem("Mydata");
Alex Kumbhani
sumber
4

Saya melihat jawabannya di sini, dan ini menjawab pertanyaan berbagi data antara pengontrol, tetapi apa yang harus saya lakukan jika saya ingin satu pengontrol memberi tahu yang lain tentang fakta bahwa data telah diubah (tanpa menggunakan siaran)? MUDAH! Hanya menggunakan pola pengunjung yang terkenal:

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

Dengan cara sederhana ini, satu pengontrol dapat memperbarui pengontrol lain yang beberapa data telah diperbarui.

Omri Lahav
sumber
2
Bukankah pola pengamat ( en.wikipedia.org/wiki/Observer_pattern ) lebih relevan di sini? Pola pengunjung adalah sesuatu yang lain ... en.wikipedia.org/wiki/Visitor_pattern
Ant Kutschera
3

Saya telah membuat pabrik yang mengontrol ruang lingkup bersama di antara pola jalur rute, sehingga Anda dapat mempertahankan data bersama hanya saat pengguna menavigasi di jalur induk rute yang sama.

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

Jadi, jika pengguna pergi ke jalur rute lain, misalnya '/ Dukungan', data bersama untuk jalur '/ Pelanggan' akan secara otomatis dihancurkan. Tetapi, jika alih-alih ini, pengguna pergi ke jalur 'anak', seperti '/ Pelanggan / 1' atau '/ Pelanggan / daftar' lingkup tidak akan hancur.

Anda dapat melihat contoh di sini: http://plnkr.co/edit/OL8of9

Oberdan Nunes
sumber
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

Pada klik Anda dapat memanggil metode yang meminta siaran:

$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

Salah satu cara menggunakan layanan sudut:

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: ''};
});
Subhransu
sumber
2
letakkan lebih banyak penjelasan dalam jawaban Anda.
Gerhard Barnard
2

Buat pabrik di modul Anda dan tambahkan referensi pabrik di controller dan gunakan variabelnya di controller dan sekarang dapatkan nilai data di controller lain dengan menambahkan referensi di mana pun Anda inginkan

Resham Kadel
sumber
2

Saya tidak tahu apakah itu akan membantu siapa pun, tetapi berdasarkan jawaban Charx (terima kasih!), Saya telah membuat layanan cache sederhana. Silakan gunakan, remix, dan bagikan:

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
    };
});
marverix
sumber
2

Salah satu cara menggunakan layanan sudut:

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/

Siwa Ganesh
sumber
1

FYI $ scope Object memiliki $ emit, $ broadcast, $ on AND $ rootScope Object memiliki $ emit, $ broadcast, $ on yang identik

baca lebih lanjut tentang mempublikasikan / berlangganan pola desain di sudut sini

Anja Ishmukhametova
sumber
1

Untuk meningkatkan solusi yang diusulkan oleh @Maxim menggunakan $ broadcast, kirim data tidak berubah

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

tetapi untuk mendengarkan data

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

Ada tiga cara untuk melakukannya,

a) menggunakan layanan

b) Mengeksploitasi tergantung hubungan orang tua / anak antara cakupan pengontrol

c) Dalam Angular 2.0 "As" kata kunci akan meneruskan data dari satu pengontrol ke yang lain.

Untuk informasi lebih lanjut dengan contoh, Silakan periksa tautan di bawah ini:

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

Shrinivas Kalangutkar
sumber
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'
}
}

Pengendali Pertama

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

Kontroler Kedua

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

saya pikir

Cara terbaik

adalah dengan menggunakan $ localStorage. (Bekerja sepanjang waktu)

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

CardController Anda akan menjadi

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

Anda juga bisa menambahkan

if($localStorage.selectedObj){
    $scope.selectedProducts = $localStorage.selectedObj;
}else{
    //redirect to select product using $location.url('/select-product')
}
shreedhar bhat
sumber