AngularJS melakukan fungsi tautan setelah respons $http dikembalikan

Saya perlu menjalankan fungsi tautan dalam arahan setelah respons http kembali. Idenya kira-kira seperti ini:

<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>

Di sini, saya perlu mengikat kolom input ke elemen respons, tetapi saya tidak tahu elemen apa yang akan dipanggil sampai saya mendapatkan respons. Tetapi ketika saya menjalankannya, tautan arahan berjalan sebelum $http selesai: urutan sebenarnya adalah

  • $http.mulai
  • fungsi tautan arahan dijalankan
  • $http.get mengembalikan kesuksesan

Saya agak akrab dengan $q, tapi saya tidak yakin bagaimana hal itu akan digunakan untuk melakukan apa yang perlu dilakukan. BTW, saya hanya menunjukkan satu kolom input yang menjalankan direktif myField, namun kemungkinan ada banyak input di halaman tersebut, dan semuanya memerlukan informasi yang sama.

Diedit untuk menambahkan lebih banyak informasi sebagai respons terhadap permintaan:

Saya memiliki layanan yang mengembalikan struktur data JSON. Saya tidak tahu sebelumnya seperti apa struktur data itu nantinya, tapi saya bisa mengetahuinya dan mencocokkan bidang tersebut dengan bidang masukan halaman saya. Saya mencoba melakukan pencocokan ini di fungsi tautan. Saya senang melakukannya di tempat lain; Saya bisa melakukannya di fungsi $http.success, tetapi itu berarti melakukan manipulasi DOM di pengontrol; dan pemahaman saya adalah bahwa manipulasi DOM hanya boleh dilakukan dalam arahan.

Inilah tampilan HTML saya:

<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">

Respon dari server akan seperti ini:

{
    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" }
        ]
      }
    ]
 }

Respons server mungkin berbeda-beda karena:

  • Mungkin ada sejumlah ekstensi ("MY_EXTENSION_NAME", dll.)
  • Ekstensi dapat dikembalikan dalam urutan apa pun
  • Mungkin ada sejumlah bidang
  • Bidang dapat dikembalikan dalam urutan apa pun

Seluruh masalahnya di sini adalah saya ingin mengonversi "[MY_EXTENSION_NAME]myFieldName" menjadi ng-model "model.extensions[0].fields[0].value. Namun, saya sekarang berpikir untuk mengubah data menjadi bentuk kanonik selama membaca akan lebih mudah, jadi ng-model bisa berupa "model.my_extension_name.myFieldName".


person fool4jesus    schedule 11.01.2014    source sumber
comment
Tidak yakin, tapi menurut saya $watch dapat membantu.   -  person Beterraba    schedule 11.01.2014
comment
mengapa Anda menggunakan $compile di dalam fungsi tautan? Anda mungkin dapat mencapai apa yang Anda perlukan dengan cakupan terisolasi menggunakan '@'. tolong jelaskan apa yang ingin Anda lakukan.   -  person Ilan Frumer    schedule 11.01.2014
comment
Maaf, saya pikir saya sudah menjelaskan apa yang ingin saya lakukan. Saya akan memperbarui.   -  person fool4jesus    schedule 11.01.2014
comment
Ngomong-ngomong, saya memanggil $compile tautan karena itu disarankan oleh orang lain di SO lain dan berhasil, tapi saya juga akan senang jika memiliki cara yang lebih baik untuk melakukannya.   -  person fool4jesus    schedule 12.01.2014


Jawaban (1)


Tidak jelas apa yang ingin Anda capai (saya yakin akan ada cara yang lebih baik), tetapi Anda dapat melakukannya seperti ini:

1.
Tentukan janji dalam cakupan Anda:

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.
Dari HTML Anda, rujuk janji tersebut untuk meneruskannya ke arahan Anda:

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

3.
Masukkan janji ini ke dalam cakupan isolasi arahan Anda:

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

4.
Dalam fungsi link Anda, daftarkan panggilan balik ketika janji diselesaikan (yaitu Anda mendapat respons terhadap permintaan Anda) dan lakukan semua manipulasi yang diperlukan:

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

Lihat juga demo singkat ini.

person gkalpak    schedule 11.01.2014
comment
Terima kasih atas saran konkritnya. Dalam gambaran yang lebih besar, saya cukup baru mengenal Angular dan saya dengan senang hati menerima saran alternatif. Apa cara yang lebih baik? Saya sebelumnya mengedit pertanyaan saya untuk memperjelas apa yang sebenarnya saya coba lakukan - saya perlu mengikat beberapa kolom input ke data, tetapi saya tidak tahu persis apa nama kolom data tersebut hingga $http.get berhasil. Saya tidak yakin bagaimana menjelaskannya lebih jelas dari itu. - person fool4jesus; 12.01.2014
comment
Yang saya maksud adalah tidak jelas apa yang ingin Anda capai di level yang lebih tinggi. Yaitu. mengapa Anda perlu memiliki beberapa kolom input yang Anda tidak tahu harus mengikat apa, dll. - person gkalpak; 12.01.2014
comment
Maaf. Karena server mungkin mengembalikan data terstruktur dengan cara yang berbeda. Ada dua tingkat hierarki, dan setiap tingkat hierarki memiliki sesuatu seperti ‹item›‹name›foo‹/name›‹value›bar‹/value›‹/item›. Yang saya tahu di atributnya adalah foo.bar... sehingga mungkin dipetakan ke atribut ng-model seperti (katakanlah) model.extensions[3].fields[4].value. Salah satu cara alternatif adalah dengan memetakan ulang data menjadi dua tingkat hash dan kemudian kembali lagi saat menyimpan; tapi menurut saya itu tidak akan terlalu membantu, karena ketika direktif dipanggil, extensions[3] belum ada. Namun saran disambut baik. :-) - person fool4jesus; 13.01.2014
comment
Daripada memiliki beberapa elemen DOM yang Anda tidak tahu apa yang harus diikat (sehingga harus menunggu respons dari server untuk memberi tahu Anda apa yang harus diikat setiap elemen), mengapa tidak menerima data dari server dan lalu masukkan elemen DOM yang sesuai (terikat ke nilai yang sesuai)? (Maaf, jika saran saya tidak masuk akal - harus saya akui saya belum bisa membayangkan 100% pengaturan Anda.) - person gkalpak; 13.01.2014
comment
Terima kasih telah tinggal bersama saya - ide yang menarik. Masalahnya adalah penulis HTML menulis elemen DOM langsung ke dalam template Angular, dan dia tahu apa yang akan dikembalikan server saat runtime; dia hanya tidak tahu persis format datanya. Salah satu kemungkinannya adalah meminta penulis menulis elemennya, namun tidak membuat arahan pada bidang tersebut sama sekali, melainkan hanya atribut biasa. Kemudian setelah kita membaca dari server, menelusuri kolom, membuat atribut ng-model, dan $kompilasinya. Itu berarti manipulasi DOM pada pengontrol. Namun, jumlahnya akan sangat minim. - person fool4jesus; 13.01.2014
comment
Ini semakin parah (kebingungan saya)! Mungkin melihat beberapa kode akan membantu memperjelas (jika Anda tidak keberatan memposting beberapa bagian yang relevan). - person gkalpak; 13.01.2014
comment
Tentu saya akan mengedit pertanyaan awal saya. BTW, saya membuatnya berfungsi dengan mengubah respons server menjadi bentuk kanonik dan kemudian mereferensikannya. - person fool4jesus; 13.01.2014
comment
Oke, saya mengerti sekarang. Saya setuju dengan komentar terakhir Anda (tentang mengubah respons untuk menyederhanakan model). Ini adalah solusi paling bersih (dan mempertahankan pemisahan kepentingan antara pengontrol, arahan, pandangan, dll.). Satu-satunya solusi yang saya ingin lebih baik adalah jika Anda dapat meminta server mengirimkan data dalam bentuk kanonik. - person gkalpak; 13.01.2014
comment
Ya, tidak banyak yang bisa saya lakukan mengenai hal itu. :-) Terima kasih atas dialognya. - person fool4jesus; 22.01.2014