AngularJS выполняет функцию ссылки после возврата ответа $http

Мне нужно выполнить функцию ссылки в директиве после возврата ответа http. Идея примерно такая:

<input type="text" my-field>
<script>
 angular.module("mine")
 .controller ('myCtrl', function ($scope) {
  $http.get("/my/service").success(function (data, status, headers, config) {
    // OK, done with the query... now I know my field name to bind to. Somehow
    // I have to get it down to the link function below...
  });
 })
 .directive ('myField', function ($compile) {
  return {
    link: function (scope, element, attrs) {
      var my_field = attrs.myField;
      element.removeAttr('my-field');

      // Somehow figure out the field here in ngFieldSpec
      element.attr('ng-model', ngFieldSpec);
      $compile(element)(scope);
    };
   });
</script>

Здесь мне нужно привязать поле ввода к элементу ответа, но я не знаю, как будет называться этот элемент, пока не получу ответ. Но когда я запускаю его, ссылка директивы запускается до того, как $http будет выполнено: фактическая последовательность

  • $http.get запускается
  • функция ссылки директивы run
  • $http.get возвращает успех

Я немного знаком с $q, но не уверен, как его можно использовать для выполнения необходимых действий. Кстати, я показал только одно поле ввода, вызывающее директиву myField, но потенциально их много на странице, и всем им нужна одна и та же информация.

Отредактировано для добавления дополнительной информации в ответ на запрос:

У меня есть служба, которая возвращает структуру данных JSON. Я не знаю заранее, как именно будет выглядеть эта структура данных, но я могу понять это и сопоставить поля с полями ввода моей страницы. Я пытаюсь сделать это сопоставление в функции ссылки. Я рад сделать это в другом месте; Я мог бы сделать это в функции $http.success, но это было бы манипулированием DOM в контроллере; и я понимаю, что манипуляции с DOM должны выполняться только в директиве.

Вот как должен выглядеть мой HTML:

<input type="text" my-field="[MY_EXTENSION_NAME]myFieldName">
<input type="text" my-field="[MY_EXTENSION_NAME]myFieldName2">
<input type="text" my-field="[MY_EXTENSION_NAME_2]myFieldName">

Ответ от сервера будет примерно таким:

{
    realField1: "Diddly",
    realField2: "Squat",
    extensions: [
      {
        name: "MY_EXTENSION_NAME",
        fields: [
          { name="myFieldName" value="Foo" },
          { name="myFieldName2" value="Bar" }
        ]
      },
      {
        name: "MY_EXTENSION_NAME_2",
        fields: [
          { name="myFieldName" value="Baz" },
          { name="myFieldName2" value="Buz" }
        ]
      }
    ]
 }

Ответ сервера может отличаться, потому что:

  • Может быть любое количество расширений ("MY_EXTENSION_NAME" и т. д.)
  • Расширения могут быть возвращены в любом порядке
  • Может быть любое количество полей
  • Поля могут быть возвращены в любом порядке

Вся проблема здесь в том, что я хочу преобразовать "[MY_EXTENSION_NAME]myFieldName" в ng-модель "model.extensions[0].fields[0].value. Однако сейчас я думаю о преобразовании данных в каноническую форму во время чтения будет проще, поэтому ng-модель может быть просто «model.my_extension_name.myFieldName».


person fool4jesus    schedule 11.01.2014    source источник
comment
Не уверен, но думаю, что $watch мог бы помочь.   -  person Beterraba    schedule 11.01.2014
comment
почему вы используете $compile внутри функции ссылки? вы, вероятно, можете добиться того, что вам нужно, с изолированной областью, используя «@». пожалуйста, опишите, что вы хотите сделать.   -  person Ilan Frumer    schedule 11.01.2014
comment
Извините, я думал, что объяснил, что я хочу сделать. Я обновлю.   -  person fool4jesus    schedule 11.01.2014
comment
Между прочим, я вызываю $compile в ссылке, потому что это было предложено кем-то другим в другом SO, и это работает, но я был бы рад иметь и лучший способ сделать это.   -  person fool4jesus    schedule 12.01.2014


Ответы (1)


Непонятно, чего вы пытаетесь достичь (я уверен, что будет лучший способ), но вы можете сделать это так:

1.
Определите обещание в своей области действия:

app.controller('myCtrl', function ($http, $scope) {
    $scope.model = {
        promise: $http.get('/my/service'),
        myField01: 'Hello, world, from 01 !',
        myField02: 'Hello, world, from 02 !',
        myField03: 'Hello, world, form 03 !'
    };
});

2.
В HTML-коде укажите ссылку на обещание, чтобы передать его в директиву:

<input type="text" my-field="model.promise" />

3.
Включите это обещание в изолирующую область действия вашей директивы:

app.directive ('myField', function ($compile) {
    return {
        scope: { promise: '=myField' },
        ...

4.
В своей функции link зарегистрируйте обратный вызов, когда обещание будет разрешено (т. е. вы получите ответ на свой запрос), и выполните все необходимые манипуляции:

...
link: function (scope, elem, attrs) {
    scope.promise.success(function (data) {
        elem.removeAttr('my-field');
        elem.attr('ng-model', 'model.' + data.fieldName);
        $compile(elem)(scope.$parent);
    });
}

См. также эту короткую демонстрацию.

person gkalpak    schedule 11.01.2014
comment
Спасибо за конкретное предложение. В целом, я довольно новичок в Angular, и я рад принять альтернативные предложения. Что может быть лучше? Ранее я редактировал свой вопрос, чтобы было ясно, что именно я пытаюсь сделать - мне нужно связать некоторые поля ввода с данными, но я точно не знаю, как называются поля данных, пока не появится $http.get удается. Я не уверен, как объяснить это более ясно, чем это. - person fool4jesus; 12.01.2014
comment
Я имел в виду, что неясно, чего вы пытаетесь достичь на более высоком уровне. т.е. почему вам нужно иметь некоторые поля ввода, которые вы не знаете, к чему привязываться и т. д. - person gkalpak; 12.01.2014
comment
Извини. Потому что сервер может возвращать данные, структурированные по-разному. Существует двухуровневая иерархия, и на каждом уровне иерархии есть что-то вроде ‹item›‹name›foo‹/name›‹value›bar‹/value›‹/item›. Все, что я знаю об атрибуте, это foo.bar... так что это может сопоставляться с атрибутом ng-модели, например, скажем, model.extensions[3].fields[4].value. Одним из альтернативных способов является переназначение данных на два уровня хэшей, а затем обратно при сохранении; но я не думаю, что это действительно поможет, потому что когда вызывается директива, extensions[3] еще не существует. Хотя предложения приветствуются. :-) - person fool4jesus; 13.01.2014
comment
Вместо того, чтобы иметь некоторые элементы DOM, к которым вы не знаете, к чему привязываться (поэтому приходится ждать ответа от сервера, чтобы сообщить вам, к чему привязать каждый элемент), почему бы не получить данные с сервера и затем вставить соответствующие элементы DOM (привязанные к соответствующим значениям) ? (Извините, если мое предложение не имеет смысла - я должен признать, что еще не могу на 100% представить вашу настройку.) - person gkalpak; 13.01.2014
comment
Спасибо, что остались со мной - интересная идея. Дело в том, что HTML-автор записывает DOM-элементы прямо в шаблон Angular, и он знает, что сервер вернет во время выполнения; он просто не знает точно формат данных. Одна из возможностей может заключаться в том, чтобы автор написал элементы, но вообще не создавал директиву для полей, а просто обычный атрибут. Затем, после того, как мы прочитаем с сервера, пройдемся по полям, создадим атрибуты ng-модели и $скомпилируем их. Однако это означает манипуляции с DOM в контроллере. Тем не менее, это было бы довольно минимально. - person fool4jesus; 13.01.2014
comment
Становится все хуже (мое замешательство)! Возможно, просмотр некоторого кода поможет прояснить ситуацию (если вы не против опубликовать некоторые соответствующие части). - person gkalpak; 13.01.2014
comment
Конечно, я отредактирую свой первоначальный вопрос. Кстати, у меня это работает, преобразовывая ответ сервера в каноническую форму, а затем ссылаясь на это. - person fool4jesus; 13.01.2014
comment
Хорошо, теперь я понимаю. Я согласен с вашим последним комментарием (о преобразовании ответа для упрощения модели). Это самое чистое решение (и сохраняет разделение задач между контроллерами, директивами, представлениями и т. д.). Единственное решение, которое я хотел бы улучшить, - это если бы вы могли, в первую очередь, чтобы сервер доставлял данные в канонической форме. - person gkalpak; 13.01.2014
comment
Да, я мало что могу с этим поделать. :-) Спасибо за диалог. - person fool4jesus; 22.01.2014