Подтвердить что ты не робот

Как передавать данные между отдельными компонентами без использования $scope?

Я создаю компонент, который содержит 3 дочерних компонента таким образом:

<header-component>
<side-component>
<main-component>

Основной компонент содержит список героев. Компонент заголовка содержит две кнопки, которые, как предполагается, должны переключать представление основного компонента на список или представление сетки.

Теперь проблема заключается в передаче данных из компонента header в основной компонент. Поэтому, когда я нажимаю кнопку сетки, вид основного содержимого должен измениться на вид сетки, то же самое для представления строки.

Как можно передавать данные между дочерними компонентами в angular 1.5?

4b9b3361

Ответ 1

Компонентный подход

Я предлагаю вам согласовать с подходом Angular 2 и использовать входы/вывод, Если вы это сделаете, вы сможете легко перейти на Angular 2, потому что компоненты будут концептуально идентичными (с разницей только в синтаксисе). Итак, вот как вы это делаете.

Таким образом, мы хотим, чтобы заголовок и основные компоненты делили часть состояния с заголовком, чтобы иметь возможность изменить его. Есть несколько подходов, которые мы можем использовать, чтобы заставить его работать, но самым простым является использование свойства промежуточного родительского контроллера. Поэтому пусть предполагается, что родительский контроллер (или компонент) определяет это свойство view, которое вы хотите использовать как заголовком (может читать и изменять), так и основными (может читать) компонентами.

Компонент заголовка: ввод и вывод.

Вот как выглядит простой компонент заголовка:

.component('headerComponent', {
  template: `
    <h3>Header component</h3>
    <a ng-class="{'btn-primary': $ctrl.view === 'list'}" ng-click="$ctrl.setView('list')">List</a>
    <a ng-class="{'btn-primary': $ctrl.view === 'table'}" ng-click="$ctrl.setView('table')">Table</a>
  `,
  controller: function() {
    this.setView = function(view) {
      this.view = view
      this.onViewChange({$event: {view: view}})
    }
  },
  bindings: {
    view: '<',
    onViewChange: '&'
  }
})

Самая важная часть здесь - привязки. В view: '<' мы указываем, что компонент header сможет читать внешнее что-то и связывать его как свойство view собственного контроллера. С onViewChange: '&' компонентами определены выходы: канал для уведомления/обновления внешнего мира с тем, что ему нужно. Компонент заголовка вытолкнет некоторые данные через этот канал, но он не знает, какой из них будет работать с родительским компонентом, и это не должно волноваться.

Таким образом, это означает, что контроллер header может использоваться как

<header-component view="root.view" on-view-change="root.view = $event.view"></header-component> 

Основной компонент: ввод.

Основной компонент проще, ему нужно только определить ввод, который он принимает:

.component('mainComponent', {
  template: `
    <h4>Main component</h4>
    Main view: {{ $ctrl.view }}
  `,
  bindings: {
    view: '<'
  }
})

Родительский просмотр

И, наконец, все они связаны друг с другом:

<header-component view="root.view" on-view-change="root.view = $event.view"></header-component>
<main-component view="root.view"></main-component>

Взгляните и играйте с простой демонстрацией.

angular.module('demo', [])

.controller('RootController', function() {
  this.view = 'table'
})

.component('headerComponent', {
  template: `
    <h3>Header component</h3>
    <a class="btn btn-default btn-sm" ng-class="{'btn-primary': $ctrl.view === 'list'}" ng-click="$ctrl.setView('list')">List</a>
    <a class="btn btn-default btn-sm" ng-class="{'btn-primary': $ctrl.view === 'table'}" ng-click="$ctrl.setView('table')">Table</a>
  `,
  controller: function() {
    this.setView = function(view) {
      this.view = view
      this.onViewChange({$event: {view: view}})
    }
  },
  bindings: {
    view: '<',
    onViewChange: '&'
  }
})

.component('mainComponent', {
  template: `
    <h4>Main component</h4>
    Main view: {{ $ctrl.view }}
  `,
  bindings: {
    view: '<'
  }
})
<script src="https://code.angularjs.org/1.5.0/angular.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />

<div class="container" ng-app="demo" ng-controller="RootController as root">
  
    <pre>Root view: {{ root.view }}</pre>
    
    <header-component view="root.view" on-view-change="root.view = $event.view"></header-component>
    <main-component view="root.view"></main-component>
    
</div>

Ответ 2

Несмотря на то, что подход с родительским компонентом (передача данных через атрибуты) является идеальной и надежной реализацией, , мы можем добиться того же самого более простым способом, используя хранилище factory.

В принципе, данные сохраняются Store, на которые ссылаются в области обоих компонентов, что позволяет реагировать на обновления пользовательского интерфейса при изменении состояния.

Пример:

angular
    .module('YourApp')
    // declare the "Store" or whatever name that make sense
    // for you to call it (Model, State, etc.)
    .factory('Store', () => {
        // hold a local copy of the state, setting its defaults
        const state = {
            data: {
              heroes: [],
              viewType: 'grid'
            }
        };
        // expose basic getter and setter methods
        return {
            get() {
                return state.data;
            },
            set(data) {
                Object.assign(state.data, data);
            },
        };
    });

Затем в ваших компонентах вы должны иметь что-то вроде:

angular
    .module('YourApp')
    .component('headerComponent', {
        // inject the Store dependency
        controller(Store) {
            // get the store reference and bind it to the scope:
            // now, every change made to the store data will
            // automatically update your component UI
            this.state = Store.get();

            // ... your code
        },
        template: `
            <div ng-show="$ctrl.state.viewType === 'grid'">...</div>
            <div ng-show="$ctrl.state.viewType === 'row'">...</div>
            ...
        `
    })
    .component('mainComponent', {
        // same here, we need to inject the Store
        controller(Store) {
            // callback for the switch view button
            this.switchViewType = (type) => {
                // change the Store data:
                // no need to notify or anything
                Store.set({ viewType: type });
            };

            // ... your code
        },
        template: `
            <button ng-click="$ctrl.switchViewType('grid')">Switch to grid</button>
            <button ng-click="$ctrl.switchViewType('row')">Switch to row</button>
            ...
        `

Если вы хотите увидеть рабочий пример, проверьте этот код .png.

Для этого вы также можете включить связь между 2 или N компонентами. Вам просто нужно:

  • ввести зависимость хранилища
  • убедитесь, что вы привязываете данные хранилища к области вашего компонента.

как в приведенном выше примере (<header-component>).

В реальном мире типичное приложение должно управлять большим количеством данных, поэтому имеет смысл логически разделять области данных каким-то образом. Следуя тому же подходу , вы можете добавить больше фабрик магазина. Например, чтобы управлять текущей зарегистрированной информацией пользователя и внешним ресурсом (т.е. Каталогом), вы можете построить UserStore плюс a CatalogStore - альтернативно UserModel и CatalogModel; эти организации также будут хорошими местами для централизации таких вещей, как общение с внутренним контентом, добавление пользовательской бизнес-логики и т.д. Управление данными будет в конечном итоге ответственностью за фабрики Store.

Имейте в виду, что мы мутируем данные хранилища. Несмотря на то, что этот подход мертв простым и понятным, он может не масштабироваться хорошо, потому что будет создавать побочные эффекты . Если вы хотите что-то более продвинутое (неизменность, чистые функции, дерево с одним состоянием и т.д.), Зайдите Redux, или если вы, наконец, захотите для перехода на Angular 2 посмотрите ngrx/store.

Надеюсь, это поможет!:)

Вам не нужно делать это Angular 2, потому что на всякий случай вы иногда мигрировали... Сделайте это, если это имеет смысл для вас сделать это.

Ответ 3

Используйте специальные события для достижения этого. вы можете передавать сообщение через ваше приложение с помощью диспетчеров событий $emit(name, args); or $broadcast(name, args); И вы можете слушать эти события, используя метод $on (name, listenener);

Надеюсь, что это поможет

Ref: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$emit

Пример: вы можете уведомлять об изменении, как показано ниже, из вашего компонента header

$rootScope.$emit("menu-changed", "list");

И вы можете слушать изменения в директиве основного компонента, например

$rootScope.$on("menu-changed", function(evt, arg){
  console.log(arg);
});