AngularJS UI Router - durumu yeniden yüklemeden url'yi değiştirin


134

Şu anda projemiz varsayılan kullanıyor $routeProviderve urlsayfayı yeniden yüklemeden değiştirmek için bu "hack" i kullanıyorum :

services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
    $location.skipReload = function () {
        var lastRoute = $route.current;
        var un = $rootScope.$on('$locationChangeSuccess', function () {
            $route.current = lastRoute;
            un();
        });
        return $location;
    };
    return $location;
}]);

ve controller

$locationEx.skipReload().path("/category/" + $scope.model.id).replace();

Ben değiştirilmesi düşünüyorum routeProviderile ui-routeriç içe rotalar için, ancak bu in bulamıyorum ui-router.

Mümkün mü - aynısını yap angular-ui-router?

Buna neden ihtiyacım var? Bir örnekle açıklayayım:
Yeni kategori yaratma rotası , KAYDET'ten /category/new sonra clickinggösteriliyor success-alertve rotayı /category/newşu şekilde değiştirmek istiyorum /caterogy/23(23 - db'de depolanan yeni öğenin kimliği)


1
ui-yönlendiricide her durum için bir URL tanımlamanız gerekmez, URL'yi değiştirmeden durumdan eyalete gidebilirsiniz
Jonathan de M.

URL'nin tamamını mı yoksa sadece arama yolunu mu güncellemek istiyorsunuz? Arama yolunu güncelleyen bir çözüm arıyordum ve burada buldum: stackoverflow.com/questions/21425378/…
Florian Loch

@johnathan Gerçekten mi? Sadece tek bir URL göstererek bunu yapmayı çok isterdim, ancak $urlRouterProvider.otherwisebir eyalet değil, bir URL üzerinde çalışıyor gibi görünüyor. Hmmm, belki 2 URL ile yaşayabilirim ya da geçersiz bir URL olduğunu belirtmenin başka bir yolunu bulabilirim.
Mawg, Monica'nın

Yanıtlar:


164

$state.transitionTo Bunun yerine basitçe kullanabilirsiniz $state.go . dahili olarak $state.go arar, $state.transitionTo ancak seçenekleri otomatik olarak olarak ayarlar { location: true, inherit: true, relative: $state.$current, notify: true } . Arayabilir $state.transitionTo ve ayarlayabilirsiniz notify: false . Örneğin:

$state.go('.detail', {id: newId}) 

ile değiştirilebilir

$state.transitionTo('.detail', {id: newId}, {
    location: true,
    inherit: true,
    relative: $state.$current,
    notify: false
})

Düzenleme: fracz tarafından önerildiği gibi basitçe şunlar olabilir:

$state.go('.detail', {id: newId}, {notify: false}) 

16
Bu, "durumu yeniden yüklemeden url'yi değiştir" yerine "durumu yeniden yüklerken url'yi koru" değil mi?
Peter Hedberg

25
benim için şunlarla çalıştı: $state.transitionTo('.detail', {id: newId}, { location: true, inherit: true, relative: $state.$current, notify: false }) bu yüzden temelde notify'ı false ve location'u doğru olarak ayarlayın
Arjen de Vries

6
@ArjendeVries Evet, beklendiği gibi çalışıyor ama beklenmedik bir davranış buldum. Birçok transitionTo yöntem çağrısıyla oynadıktan sonra (yeniden yüklemeden), nihayet yeni bir duruma (örn. Url) geçtiğinizde, eski denetleyiciyi yeniden başlatır.
Premchandra Singh

2
@Premchandra Singh: Aynı sorunu burada yaşıyorum. Durumdan çıkarken, eski kontrolör yeniden başlatılır. Wiherek'ten kabul edilen çözümle aynı sorunu yaşıyorum. Ayrıca buraya bakın github.com/angular-ui/ui-router/issues/64
martinoss

15
Hatta daha basit: $state.go('.detail', {id: newId}, {notify: false}).
fracz

48

Tamam, çözüldü :) Angular UI Router bu yeni yönteme sahip, $ urlRouterProvider.deferIntercept () https://github.com/angular-ui/ui-router/issues/64

temelde şuna geliyor:

angular.module('myApp', [ui.router])
  .config(['$urlRouterProvider', function ($urlRouterProvider) {
    $urlRouterProvider.deferIntercept();
  }])
  // then define the interception
  .run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
    $rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
      // Prevent $urlRouter's default handler from firing
      e.preventDefault();

      /** 
       * provide conditions on when to 
       * sync change in $location.path() with state reload.
       * I use $location and $state as examples, but
       * You can do any logic
       * before syncing OR stop syncing all together.
       */

      if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
        // your stuff
        $urlRouter.sync();
      } else {
        // don't sync
      }
    });
    // Configures $urlRouter's listener *after* your custom listener
    $urlRouter.listen();
  }]);

Sanırım bu yöntem şu anda yalnızca açısal ui yönlendiricinin ana sürümüne dahil edildi, isteğe bağlı parametrelere sahip olan (ki bunlar da güzel, btw). Kaynaktan klonlanması ve oluşturulması gerekir.

grunt build

Dokümanlara kaynaktan da erişilebilir.

grunt ngdocs

(/ site dizinine yerleştirilirler) // README.MD'de daha fazla bilgi

Bunu yapmanın dinamik parametrelerle (kullanmadığım) başka bir yolu var gibi görünüyor . Nateabele'ye birçok kredi.


Bir yan not olarak, Angular UI Router'ın $ stateProvider'ında yukarıdakilerle kombinasyon halinde kullandığım isteğe bağlı parametreler :

angular.module('myApp').config(['$stateProvider', function ($stateProvider) {    

  $stateProvider
    .state('main.doorsList', {
      url: 'doors',
      controller: DoorsListCtrl,
      resolve: DoorsListCtrl.resolve,
      templateUrl: '/modules/doors/doors-list.html'
    })
    .state('main.doorsSingle', {
      url: 'doors/:doorsSingle/:doorsDetail',
      params: {
        // as of today, it was unclear how to define a required parameter (more below)
        doorsSingle: {value: null},
        doorsDetail: {value: null}
      },
      controller: DoorsSingleCtrl,
      resolve: DoorsSingleCtrl.resolve,
      templateUrl: '/modules/doors/doors-single.html'
    });

}]);

bunun yaptığı şey, parametrelerden biri eksik olsa bile bir durumu çözmeye izin vermektir. SEO bir amaç, okunabilirlik başka bir amaçtır.

Yukarıdaki örnekte, doorsSingle'ın gerekli bir parametre olmasını istedim. Bunların nasıl tanımlanacağı belli değil. Birden fazla isteğe bağlı parametrede sorunsuz çalışır, bu yüzden gerçekten bir sorun değildir. Tartışma burada https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090


Görünüşe göre isteğe bağlı parametreler şeyiniz çalışmıyor. Error: Both params and url specicified in state 'state'. Dokümanlarda bunun da geçersiz kullanım olduğu yazıyor . Biraz hayal kırıklığına ugratici.
Rhys van der Waerden

1
Ustadan mı inşa ettin? Çözümü eklediğim noktada, isteğe bağlı parametrelerin yalnızca kaynaktan manuel olarak oluşturulması gereken sürüme dahil edildiğini lütfen unutmayın. bu, v.0.3 çıkıncaya kadar sürüme dahil edilmeyecektir.
wiherek

1
Sadece hızlı bir not. Nateabele sayesinde, birkaç gün önce piyasaya sürülen isteğe bağlı parametreler v0.2.11'de mevcuttur.
rich97

bu çok kafa karıştırıcı: $ urlRouterProvider.deferIntercept (); denetleyiciyi yeniden yüklemeden parametreleri güncelleyebilmem için? Bu bana bunu gerçekten göstermiyor. Run işlevi içinde bir if ifadesini eşitlemek veya eşitlememek için değerlendirebilirsiniz, ancak tek çalışmam gereken eski ve yeni url'dir. Bunun, tek yapmak istediğim tek şeyin, üzerinde çalışmak için yalnızca iki url ile parametreleri güncellemek olduğu bir örnek olduğunu nasıl bilebilirim? Mantık .... olur mu (eski durum ve yeni durum aynıysa denetleyiciyi yeniden yüklemeyin mi?) Kafam karıştı.
btm1

doğru, bu kullanım durumunun iç içe geçmiş durumlarla olduğunu düşünüyorum, alt durumu yeniden yüklemek istemedim, bu yüzden araya giriyordu. Sanırım şimdi bunu mutlak hedefleme görüşleriyle yapmayı ve değişmeyeceğini bildiğim duruma ilişkin görüşü tanımlamayı tercih ederim. Her neyse, bu hala iyi. Tam url'ler alırsınız, yani durumu url'den tahmin edebilirsiniz. Ve ayrıca sorgu ve yol parametreleri, vb. Uygulamanızı eyaletler ve url'ler etrafında yapıyorsanız, bu çok fazla bilgi demektir. Çalıştırma bloğunda ayrıca hizmetlere vb. Erişebilirsiniz. Bu sorunuza cevap veriyor mu?
wiherek

16

Bu sorunla çok zaman geçirdikten sonra işte çalıştığım şey

$state.go('stateName',params,{
    // prevent the events onStart and onSuccess from firing
    notify:false,
    // prevent reload of the current state
    reload:false, 
    // replace the last record when changing the params so you don't hit the back button and get old params
    location:'replace', 
    // inherit the current params on the url
    inherit:true
});

Diğer çözümler yol sağlayıcıyla ilgilidir. Bu çözüm, benimki gibi, $ stateProvider kullandığım ve $ routeProvider kullanmadığım durum için çalışıyor.
eeejay

@eeejay temelde soru için istendi ui-routersadece, bunu, diğer çözümler için çalışıyorlardı söyleyebiliriz nasıl $routerProvider, $routeProviderve $stateProvidermimaride tamamen farklı ..
Pankaj Parkar

ya geri düğmesinin bununla çalışmasını istemiyorsak? Demek istediğim, geri basıldığında önceki duruma / url'ye git, farklı parametrelerle aynı duruma değil
gaurav5430

Sanırım, bu çözüm tarayıcısı tarafından geri çalışmayacaktır, çünkü bir durumu ui yönlendiriciye bildirmeden değiştiriyoruz
Pankaj Parkar

2
Bunu denedim ve görünüşe göre $onInit()bileşenim her $state.go. Bana% 100 uygun görünmüyor.
Carrm

8

çağrı

$state.go($state.current, {myParam: newValue}, {notify: false});

yine de denetleyiciyi yeniden yükleyecektir.

Bundan kaçınmak için parametreyi dinamik olarak tanımlamanız gerekir:

$stateProvider.state({
    name: 'myState',
    url: '/my_state?myParam',
    params: {
        myParam: {
          dynamic: true,
        }
    },
    ...
});

O zaman ihtiyacın bile yok notify, sadece arıyorsun

$state.go($state.current, {myParam: newValue})

yeterli. Neato!

Gönderen belgeler :

Olduğunda dynamic, trueparametre değerinde yapılan değişiklikler duruma girilmesine / çıkılmasına neden olmaz. Çözümler yeniden getirilmeyecek ve görünümler yeniden yüklenmeyecek.

[...]

Bu, param değerleri değiştiğinde bileşenin kendini güncellediği UI oluşturmak için yararlı olabilir.


7

Bu kurulum benim için aşağıdaki sorunları çözdü:

  • Dan url güncellerken eğitim kontrolörü iki kez çağrılmaz .../için.../123
  • Eğitim denetleyicisi başka bir duruma geçerken tekrar çağrılmıyor

Durum yapılandırması

state('training', {
    abstract: true,
    url: '/training',
    templateUrl: 'partials/training.html',
    controller: 'TrainingController'
}).
state('training.edit', {
    url: '/:trainingId'
}).
state('training.new', {
    url: '/{trainingId}',
    // Optional Parameter
    params: {
        trainingId: null
    }
})

Durumları çağırmak (başka herhangi bir denetleyiciden)

$scope.editTraining = function (training) {
    $state.go('training.edit', { trainingId: training.id });
};

$scope.newTraining = function () {
    $state.go('training.new', { });
};

Eğitim Kontrolörü

var newTraining;

if (!!!$state.params.trainingId) {

    // new      

    newTraining = // create new training ...

    // Update the URL without reloading the controller
    $state.go('training.edit',
        {
            trainingId : newTraining.id
        },
        {
            location: 'replace', //  update url and replace
            inherit: false,
            notify: false
        });     

} else {

    // edit

    // load existing training ...
}   

Benzer bir strateji kullanmaya çalışıyordum ama denetleyicim eğitimin değerini asla düzenleme sayfasından almıyor, orada eksik olabileceğim herhangi bir şey var mı? Düzenleme sayfasına doğrudan URL'den ve ui-sref kullanarak erişmeyi denedim. Benim kodum tam olarak seninki gibi.
Nikhil Bhandari

Bu benim için çalıştı ve açık ara en net çözüm oldu
OoDeLally

3

Yalnızca url'yi değiştirmeniz gerekiyor, ancak durumu değiştirmeyi engelliyorsanız:

Şununla konumu değiştirin (geçmişte değiştirmek istiyorsanız .replace ekleyin):

this.$location.path([Your path]).replace();

Eyaletinize yeniden yönlendirmeyi önleyin:

$transitions.onBefore({}, function($transition$) {
 if ($transition$.$to().name === '[state name]') {
   return false;
 }
});

2

Bunu uzun zaman önce yaptım: UI-yönlendiricinin v0.2.10 sürümünde şöyle bir şey gibi:

$stateProvider
  .state(
    'home', {
      url: '/home',
      views: {
        '': {
          templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
          controller: 'mainCtrl'
        },
      }
    })
  .state('home.login', {
    url: '/login',
    templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
    controller: 'authenticationCtrl'
  })
  .state('home.logout', {
    url: '/logout/:state',
    controller: 'authenticationCtrl'
  })
  .state('home.reservationChart', {
    url: '/reservations/?vw',
    views: {
      '': {
        templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
        controller: 'reservationChartCtrl',
        reloadOnSearch: false
      },
      'viewVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
        controller: 'viewVoucherCtrl',
        reloadOnSearch: false
      },
      'addEditVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
        controller: 'voucherCtrl',
        reloadOnSearch: false
      }
    },
    reloadOnSearch: false
  })

0

Bunun gibi bir şey dene

$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})

-6

Bunun için ui yönlendiriciye ihtiyacınız olduğunu sanmıyorum. $ Location hizmeti için mevcut dokümantasyon ilk paragrafta "... $ location'da yapılan değişiklikler tarayıcının adres çubuğuna yansıtılır." Daha sonra "Ne yapmaz? Tarayıcı URL'si değiştirildiğinde tam sayfanın yeniden yüklenmesine neden olmaz" demeye devam eder.

Öyleyse, bunu akılda tutarak, neden basitçe $ location.path'i (yöntem hem alıcı hem de ayarlayıcı olduğu için) aşağıdaki gibi bir şeyle değiştirmiyorsunuz:

var newPath = IdFromService;
$location.path(newPath);

Dokümantasyon notları yolu daima eğik çizgi ile başlaması gerektiğini, ancak eksik olursa bu ekleyecektir.


Kullandığım zaman ui-router ve kullanımını $location.path(URL_PATH), otomatik olarak sayfa-kılan yeniden ?!
Kousha

evet, yeniden işliyor. $ LocationChangeStart üzerinde event.preventDefault () ile denedim, bu da çalışmıyor - yani durumun yeniden oluşturulmasını durduruyor, ancak url'nin güncellenmesini de engelliyor.
wiherek
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.