AngularJs: как передать часть моих данных из одного компонента в другой

У меня есть элемент управления angular, который я использую для отображения набора данных, который выглядит примерно так, как показано в следующем примере. Помимо уникального блока, он имеет ряд повторяющихся (но дискретных) блоков одинаковой структуры.

{
  "person": {
    "lastName": "Bettertester",
    "firstName": "Fester",
    "address": "Out in the woods 17",
    "zipCode": "10666",
    "place": "Back of beyond"
  },
  "contact1": {
    "firstName": "Jane",
    "lastName": "Doe",
    "phone": "555-987-654",
    "relationship": "Aunt"
  },
  "contact2": {
    "firstName": "Kherumple",
    "lastName": "Whaduffle",
    "phone": "555-666-000",
    "relationship": "Imaginary friend"
  },
  "contact3": {
    "firstName": "Kherumple",
    "lastName": "Whaduffle",
    "phone": "555-666-000",
    "relationship": "Imaginary friend"
  }
}

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

angular.module('myModule').component('mainComponent', {
  templateUrl : 'person.template.html',
  controller : [ '$scope', '$http', function mainController($scope, $http) {
    var self = this;
    self.data = null;
    $http.get(url).then(function(response) {
      self.data = response.data;
    }, function(response, status) {
      console.warn("Error while loading data");
      console.warn(" - response=", response);
      console.warn(" - status=", status);
      self.data = null;
    });
  } ]
});

Соответствующий шаблон:

<div>
  <h1>Person information</h1>
  <table>
  <tr>
    <th class="label-column">First & last name</th>
    <td class="data">{{$ctrl.data.person.firstName}} {{$ctrl.data.person.lastName}}</td>
  </tr>
  <tr>
    <th class="label-column">Address</th>
    <td class="data">{{$ctrl.data.person.address}}</td>
  </tr>
  <tr>
    <th class="label-column">ZIP code & Place</th>
    <td class="data">{{$ctrl.data.person.zipCode}} {{$ctrl.data.person.place}}</td>
  </tr>
  </table>

  <contact details="{{$ctrl.data.contact1}}"></contact> <!-- passing the details like this sort of works -->
  <contact details="{{$ctrl.data.contact2}}"></contact>
  <contact details="$ctrl.data.contact3"></contact>     <!-- passing the details like this does not work at all -->
</div>

Контроллер контактной информации выглядит следующим образом:

angular.module('myModule').component('contact', {
  templateUrl : 'contact.template.html',
  bindings : {
    details : '@'
  },
  controller : [ '$scope', '$http', function contactController($scope, $http) {
    var self = this;
    console.log("- details=", self.details);
  } ]
});

И соответствующий шаблон:

<div>
  <h2>Contact</h2>
  <table>
  <!-- this works -->
  <tr>
    <th class="label-column">Everything</th>
    <td class="data">{{$ctrl.details}}</td>
  </tr>
  <tr>
    <th class="label-column">First & last name</th>
    <td class="data">{{$ctrl.details.firstName}} {{$ctrl.details.lastName}}</td>
  </tr>
  <tr>
    <th class="label-column">Phone</th>
    <td class="data">{{$ctrl.details.phone}}</td>
  </tr>
  <tr>
    <th class="label-column">Relationship</th>
    <td class="data">{{$ctrl.details.relationship}}</td>
  </tr>
  </table>

  <contact details="{{$ctrl.data.contact1}}"></contact>
  <contact details="{{$ctrl.data.contact2}}"></contact>
  <contact details="{{$ctrl.data.contact3}}"></contact>
  <contact details="{{$ctrl.data.contact4}}"></contact>
</div>

Мои вопросы заключаются в том, как правильно передать контактные данные, которые являются частью mainComponent, в contactComponent таким образом, чтобы я мог получить доступ к его полям в соответствующем шаблоне. Если я передам их без фигурных скобок, контактный компонент вообще не получит никаких данных. Если я передам их с помощью фигурных скобок, контактный компонент, похоже, получит их каким-то образом, но не как правильный объект json, поскольку я не могу получить доступ к полям в контактном блоке. Я уверен, что мне не хватает чего-то тривиального, но мне не удалось выяснить, где я ошибаюсь.


person Urs Beeli    schedule 28.05.2017    source источник
comment
(1) используйте details="$ctrl.data.contact1" и details : '=' (2) используйте объект $scope для доступа к данным, переданным компоненту, это должно быть $scope.details, а не self.details   -  person Abdo Adel    schedule 29.05.2017
comment
@Abdo Adel: я думаю, что нам не нужно использовать $scope, и это назначается self. так что self.details будет достаточно   -  person Kanagu    schedule 29.05.2017


Ответы (3)


  1. Используйте одностороннюю привязку < вместо привязки интерполяции @, потому что @ отслеживает интерполяцию и, если интерполяции нет, просто передает необработанную строку атрибута как само значение. < или = привязка следит за изменением выражения и соответственно обновляет шаблон значением выражения. В этом конкретном случае < более удобен, чем =, потому что нам нужно только наблюдать за изменениями ввода для компонента, нам не нужно, чтобы эти дополнительные часы воздействовали на родителя обратно, изменяя то же выражение.

  2. После применения < безопасно используйте значения атрибутов без фигурных скобок.

  3. Инициализируйте логику вашего компонента в хуке жизненного цикла контроллера $onInit, потому что этот хук вызывается после инициализации привязок, что было точной причиной того, почему ваш console.log("- details=", this.details); давал - details=undefined в contact контроллере.

Детали кода:

let app = angular.module('app', []);

app.component('mainComponent', {
  template: `
  <div>
  <h1>Person information</h1>
  <table>
  <tr>
    <th class="label-column">First & last name</th>
    <td class="data">{{$ctrl.data.person.firstName}} {{$ctrl.data.person.lastName}}</td>
  </tr>
  <tr>
    <th class="label-column">Address</th>
    <td class="data">{{$ctrl.data.person.address}}</td>
  </tr>
  <tr>
    <th class="label-column">ZIP code & Place</th>
    <td class="data">{{$ctrl.data.person.zipCode}} {{$ctrl.data.person.place}}</td>
  </tr>
  </table>

  <contact details="$ctrl.data.contact1"></contact> <!-- passing the details like this sort of works -->
  <contact details="$ctrl.data.contact2"></contact>
  <contact details="$ctrl.data.contact3"></contact>     <!-- passing the details like this does not work at all -->
</div>
  `,
  controller: ['$scope', '$http', function mainController($scope, $http) {
  
    var self = this;
    
    self.$onInit = () => {
      self.data = {
        "person": {
          "lastName": "Bettertester",
          "firstName": "Fester",
          "address": "Out in the woods 17",
          "zipCode": "10666",
          "place": "Back of beyond"
        },
        "contact1": {
          "firstName": "Jane",
          "lastName": "Doe",
          "phone": "555-987-654",
          "relationship": "Aunt"
        },
        "contact2": {
          "firstName": "Kherumple",
          "lastName": "Whaduffle",
          "phone": "555-666-000",
          "relationship": "Imaginary friend"
        },
        "contact3": {
          "firstName": "Kherumple",
          "lastName": "Whaduffle",
          "phone": "555-666-000",
          "relationship": "Imaginary friend"
        }
      };
    };
    
  }]
});

app.component('contact', {
  template: `
    <div>
  <h2>Contact</h2>
  <table>
  <!-- this works -->
  <tr>
    <th class="label-column">Everything</th>
    <td class="data">{{$ctrl.details}}</td>
  </tr>
  <tr>
    <th class="label-column">First & last name</th>
    <td class="data">{{$ctrl.details.firstName}} {{$ctrl.details.lastName}}</td>
  </tr>
  <tr>
    <th class="label-column">Phone</th>
    <td class="data">{{$ctrl.details.phone}}</td>
  </tr>
  <tr>
    <th class="label-column">Relationship</th>
    <td class="data">{{$ctrl.details.relationship}}</td>
  </tr>
  </table>
</div>
  `,
  bindings: {
    details: '<'
  },
  controller: ['$scope', '$http', function jassMonitorHandController($scope, $http) {
    this.$onInit = () => {
      console.log("- details=", this.details);
    };
  }]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>

<div ng-app="app">
    <main-component></main-component>
</div>

person Karen Grigoryan    schedule 28.05.2017

Проблема заключается в привязке details в вашем компоненте contact.

Это должно быть details: '<' (односторонняя привязка) вместо details: '@' (однократная привязка строки). При использовании этого типа привязки вам не понадобятся фигурные скобки в вашем шаблоне.

person yadejo    schedule 28.05.2017

Я думаю, что вы могли бы переписать свой компонент, чтобы получить массив контактов и использовать директиву ng-repeat

<div ng-repeat='item in contactList'>
  <table>//your stuff</table>

Передайте данные с привязками, используя оператор равенства, чтобы получить ng-модель

bindings: '='

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

Полезные ресурсы

person JorgeTovar    schedule 28.05.2017