pengembangan-web-mp-pd.com

Angular-ui.router: Perbarui URL tanpa menyegarkan tampilan

Saya memiliki Angular SPA yang menyajikan berbagai daftar rekomendasi, dan Google Map lokasi, berdasarkan potongan berbeda dari beberapa data restoran (lihat m.amsterdamfoodie.nl ). Saya ingin masing-masing daftar ini memiliki URL mereka sendiri. Agar Google dapat merayapi daftar yang berbeda, saya menggunakan tag <a> untuk navigasi offcanvas.

Saat ini tag <a> menyebabkan refresh tampilan, yang sangat terlihat dengan peta.

  • Saya dapat mencegah hal ini menggunakan ng-click dan $event.preventDefault() (lihat cuplikan kode di bawah), tetapi kemudian saya perlu mengimplementasikan cara memperbarui URL browser.
  • Tetapi dalam mencoba $state Angular atau history.pushstate browser, saya akhirnya memicu perubahan status dan tampilan refresh ...!

Karena itu pertanyaan saya adalah bagaimana saya bisa memperbarui model dan URL, tetapi tanpa menyegarkan tampilan? (Lihat juga Sudut/UI-Router - Bagaimana Saya Dapat Memperbarui URL Tanpa Menyegarkan Segalanya? )

Saya telah bereksperimen dengan banyak pendekatan dan saat ini memiliki html ini

<a href="criteria/price/1" class="btn btn-default" ng-click="main.action($event)">Budget</a>

Di controller:

this.action = ($event) ->
    $event.preventDefault()
    params = $event.target.href.match(/criteria\/(.*)\/(.*)$/)

    # seems to cause a view refresh
    # history.pushState({}, "page 2", "criteria/"+params[1]+"/"+params[2]);

    # seems to cause a view refresh
    # $state.transitionTo 'criteria', {criteria:params[1], q:params[2]}, {inherit:false}

    updateModel(...)

Dan, apa yang saya pikir sedang terjadi adalah saya memicu kode $stateProvider:

angular.module 'afmnewApp'
.config ($stateProvider) ->
  $stateProvider
  .state 'main',
    url: '/'
    templateUrl: 'app/main/main.html'
    controller: 'MainCtrl'
    controllerAs: 'main'
  .state 'criteria',
    url: '/criteria/:criteria/:q'
    templateUrl: 'app/main/main.html'
    controller: 'MainCtrl'
    controllerAs: 'main'

Satu kemungkinan petunjuk adalah bahwa dengan kode di bawah ini jika saya memuat mis. http://afmnew.herokuapp.com/criteria/cuisine/italian maka tampilan menyegarkan saat Anda menavigasi, sedangkan jika saya memuat http://afmnew.herokuapp.com/ tidak ada refresh, tetapi sebaliknya tidak ada pembaruan URL. Saya tidak mengerti mengapa itu terjadi sama sekali.

23
Simon H

Berdasarkan diskusi kami sebelumnya, saya ingin memberi Anda beberapa ide, bagaimana cara menggunakan UI-Router di sini. Saya percaya, saya memahami tantangan Anda dengan benar ... Ada contoh yang bagus . Jika ini tidak sepenuhnya suite, silakan anggap sebagai inspirasi

DISCLAIMER: Dengan seorang plunker, saya tidak dapat mencapai ini: http://m.amsterdamfoodie.nl/ , tetapi prinsipnya harus dalam contoh serupa

Jadi, ada definisi state (kami hanya memiliki dua state)

  $stateProvider
    .state('main', {
        url: '/',
        views: {
          '@' : {
            templateUrl: 'tpl.layout.html',
            controller: 'MainCtrl',
          },
          '[email protected]' : { templateUrl: 'tpl.right.html',}, 
          '[email protected]' : {
            templateUrl: 'tpl.map.html',
            controller: 'MapCtrl',
          },
          '[email protected]' : {
            templateUrl: 'tpl.list.html',
            controller: 'ListCtrl',
          },
        },
      })
    .state('main.criteria', {
        url: '^/criteria/:criteria/:value',
        views: {
          'map' : {
            templateUrl: 'tpl.map.html',
            controller: 'MapCtrl',
          },
          'list' : {
            templateUrl: 'tpl.list.html',
            controller: 'ListCtrl',
          },
        },
      })
}];

Ini akan menjadi tpl.layout.html utama kami

<div>

  <section class="main">

    <section class="map">
      <div ui-view="map"></div>
    </section>

    <section class="list">
      <div ui-view="list"></div>
    </section>

  </section>

  <section class="right">
    <div ui-view="right"></div>
  </section>

</div>

Seperti yang dapat kita lihat, negara utama menargetkan tampilan bersarang dari negara utama ini: 'viewName @ main', mis. '[email protected]'

Juga subview, main.criteria tidak menyuntikkan ke tampilan layout

Urlnya dimulai dengan tanda ^ (url : '^/criteria/:criteria/:value'), yang memungkinkan untuk memiliki / garis miring untuk main dan bukan garis miring dua untuk anak

Dan juga ada pengendali, mereka di sini agak naif, tetapi mereka harus menunjukkan, bahwa di latar belakang bisa jadi memuat data nyata (berdasarkan kriteria).

Hal terpenting di sini adalah, PARENT MainCtrl menciptakan $scope.Model = {}. Properti ini akan (berkat warisan) dibagi di antara orang tua dan anak-anak. Itu sebabnya ini semua akan bekerja:

app.controller('MainCtrl', function($scope)
{
  $scope.Model = {};
  $scope.Model.data = ['Rest1', 'Rest2', 'Rest3', 'Rest4', 'Rest5'];  
  $scope.Model.randOrd = function (){ return (Math.round(Math.random())-0.5); };
})
.controller('ListCtrl', function($scope, $stateParams)
{
  $scope.Model.list = []
  $scope.Model.data
    .sort( $scope.Model.randOrd )
    .forEach(function(i) {$scope.Model.list.Push(i + " - " + $stateParams.value || "root")})
  $scope.Model.selected = $scope.Model.list[0];
  $scope.Model.select = function(index){
    $scope.Model.selected = $scope.Model.list[index];  
  }
})

Ini seharusnya mendapatkan beberapa ide bagaimana kita dapat menggunakan fitur yang disediakan untuk kita oleh UI-Router:

Periksa ekstrak di atas di sini , di contoh kerja

Perpanjang: plunker baru di sini

Jika kita tidak ingin tampilan peta dibuat ulang, kita bisa menghilangkan yang membentuk def status anak:

.state('main.criteria', {
    url: '^/criteria/:criteria/:value',
    views: {
      // 'map' : {
      //  templateUrl: 'tpl.map.html',
      //  controller: 'MapCtrl',
      //},
      'list' : {
        templateUrl: 'tpl.list.html',
        controller: 'ListCtrl',
      },
    },
  })

Sekarang peta kita LIHAT hanya akan menerima perubahan dalam model (bisa ditonton) tetapi tampilan dan pengontrol tidak akan dirender ulang

JUGA, ada plunker lain http://plnkr.co/edit/y0GzHv?p=preview yang menggunakan controllerAs

.state('main', {
    url: '/',
    views: {
      '@' : {
        templateUrl: 'tpl.layout.html',
        controller: 'MainCtrl',
        controllerAs: 'main',        // here
      },
      ...
    },
  })
.state('main.criteria', {
    url: '^/criteria/:criteria/:value',
    views: {
      'list' : {
        templateUrl: 'tpl.list.html',
        controller: 'ListCtrl',
        controllerAs: 'list',      // here
      },
    },
  })

dan itu bisa digunakan seperti ini:

<h4>{{main.hello()}}</h4>
<h4>{{list.hello()}}</h4>

Plunker terakhir adalah di sini

11
Radim Köhler

Ini adalah contoh cara untuk pergi jika saya mengerti dengan benar:

$state.go('my.state', {id:data.id}, {notify:false, reload:false});
//And to remove the id from the url:
$state.go('my.state', {id:undefined}, {notify:false, reload:false});

Dari pengguna l-liava-l dalam masalah https://github.com/angular-ui/ui-router/issues/64

Anda dapat memeriksa API $state di sini: http://angular-ui.github.io/ui-router/site/#/api/ui.router.state . $ State

16
John Bernardsson

anda dapat menggunakan pewarisan lingkup untuk memperbarui url tanpa tampilan yang menyegarkan

$stateProvider
            .state('itemList', {
                url: '/itemlist',
                templateUrl: 'Scripts/app/item/ItemListTemplate.html',
                controller: 'ItemListController as itemList'
                //abstract: true //abstract maybe?
            }).state('itemList.itemDetail', {
                url: '/:itemName/:itemID',
                templateUrl: 'Scripts/app/item/ItemDetailTemplate.html',
                controller: 'ItemDetailController as itemDetail',
                resolve: {
                    'CurrentItemID': ['$stateParams',function ($stateParams) {
                        return $stateParams['itemID'];
                    }]
                }
            })

jika tampilan anak berada di dalam tampilan induk, kedua kontroler memiliki ruang lingkup yang sama . sehingga Anda dapat menempatkan tampilan dummy (atau perlu) di dalam tampilan induk yang akan diisi oleh tampilan anak.

dan masukkan a 

$scope.loadChildData = function(itemID){..blabla..};

berfungsi di controller orangtua yang akan dipanggil oleh child controller pada beban controller. jadi ketika pengguna mengklik 

<a ui-sref="childState({itemID: 12})">bla</a> 

hanya pengendali anak dan tampilan anak yang akan di-refresh. maka Anda dapat memanggil fungsi lingkup induk dengan parameter yang diperlukan.

2
bahadir

Jawaban singkatnya adalah jangan jangan letakkan peta di dalam tampilan yang berubah. Jawaban yang diterima memberikan lebih banyak detail tentang bagaimana membuat struktur halaman dengan sub-view, tetapi titik kuncinya bukan membuat peta bagian dari tampilan tetapi untuk menghubungkan perilakunya ke tampilan yang berubah dan menggunakan Controller untuk perbarui ikon pasar.

0
Simon H