Ember.js: definir uma propriedade de controlador em `setupController` não atualiza o parâmetro de consulta

Criado em 21 ago. 2014  ·  29Comentários  ·  Fonte: emberjs/ember.js

se você tiver um controlador definido como

App.IndexController = Ember.Controller.extend({
  queryParams: ['foo'],
  foo: ''
});

e no SetupController de Rotas você faz algo como ...

setupController: function(controller, model){
  controller.set('model', model);
  controller.set('foo', 'bar'); // <-- setting this should update the query param
}

O parâmetro de consulta não é definido no url.

Você pode ver uma caixa de trabalho aqui: http://emberjs.jsbin.com/dekuj/1/edit

Bug Inactive Query Params

Comentários muito úteis

Eu também estou vendo esse problema no Ember 2.11, tentar limpar um parâmetro de consulta no controlador não tem efeito. A solução alternativa de @barelyknown me leva a maior parte do caminho, mas ainda consideraria isso um bug aberto.

Todos 29 comentários

Corrigido com Ember.run.later (para garantir que as coisas tenham se materializado totalmente primeiro): http://emberjs.jsbin.com/kowoqo/1/edit

@machty - Qual é o comportamento esperado aqui?

Achei que tínhamos testes explícitos para esta ... verificação.

Acho que é um bug ... temos testes para isso, mas apenas no contexto de transitionTo e não na inicialização inicial do aplicativo.

trabalhando: http://jsbin.com/mejeto/1#/about

Eu adicionei um teste de falha para este bug https://github.com/emberjs/ember.js/pull/5473
Tentaremos tentar consertar isso

Acho que me deparei com um problema relacionado, então não tenho certeza se precisa de um tíquete separado aqui no GitHub.

export default Ember.Controller.extend({
    queryParams: ['modal'],
    modal: null,
    handleModal: function () {
        this.send('openModal', this.get('modal'));
    }.observes('modal')
});
export default Ember.Route.extend({
    actions: {
        openModal: function (name) {
            return this.render(name, {
                into: 'application',
                outlet: 'modal'
            });
        }
    }
});

Isso funciona em todos os casos, exceto na inicialização, quando lança Error while processing route: index Nothing handled the action 'openModal'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.

Pode ser corrigido usando Ember.run.next

handleModal: function () {
    Ember.run.next(this, function () {
        this.send('openModal', this.get('modal'));
    });
}.observes('modal')

embora pareça errado.

JSBins:
Sem Ember.run.next gera erro
Com Ember.run.next imprime 'redered' no console

@ Igor10k Estou enfrentando exatamente o mesmo problema, modal e tudo. Envolvê-lo em Ember.run.next corrige o problema, mas parece errado para mim também.

Alguém pode confirmar que isso ainda é um problema no 1.8?

@wagenet sim, isso ainda é um problema no 1.8:
http://emberjs.jsbin.com/lezuhu/1/edit?html , js, output

e canário:
http://emberjs.jsbin.com/doyohe/1/edit?html , js, output

@machty - Pensamentos?

Eu acho que isso também é um bug para mim usando 1.8.1. O que eu quero fazer é chamar um método especial no meu controlador toda vez que um queryParam específico muda. Eu tenho um roteador parecido com este.
Algum conselho?

// ...snip...

// for pagination
queryParams: {
  offset: {
    refreshModel: true
  }
},

model: function(params) {
  // returns model
},

setupController: function(controller, model) {
  this._super(controller, model);
  controller.set('model', model);

  // Fetch results is a method that does a bunch work
  // sets up some filters, generates a promise, resolves that promise
  // and then sets some array data on the controller once promise resolves.
  // offset is a pagination feature which determines which specific results
  // are fetched. I would like to be able to call fetchResults everytime the
  // offset queryParam is changed. 
  Ember.run.later(function() {
    controller.sendAction('fetchResults');
  })
}

// ...snip...

@machty - Idéias sobre por onde começar a cavar nisso?

Estou tendo o mesmo problema. this.set () no controlador não atualizará o parâmetro de consulta na URL

App.SearchController = Ember.Controller.extend ({
queryParams: ['domínio'],
domínio: nulo,

domainField: Ember.computed.oneWay ('domínio'),
ações: {
searchSubmit: function () {
this.set ('domínio', this.get ('domainField')); // Isso define o parâmetro 'domínio', mas não modifica o URL. Portanto, o modelo em App.SearchRoute nunca é chamado como esperado
}
},
});

App.SearchRoute = Ember.Route.extend ({
queryParams: {
domínio: {
refreshModel: true // Opte pela transição completa
},

},
modelo: função (params) {
var domain = params.queryParams.domain;

  return $.getJSON('/search?domain=usv.com&name=').then(function(resp){
  console.log(resp);
  return resp.data;
});

},
ações: {
atualizar: function () {
Ember.Logger.log ('A rota agora está atualizando ...');
this.refresh ();
}
},
});

Você pode fornecer uma solução nesse ínterim?

Para esclarecer: this.set () em meu código fará a alteração no objeto Class, mas não altera o URL de forma alguma

Isso é antigo, mas parece que ainda é um problema? Não consigo descobrir as circunstâncias, mas periodicamente quando tento definir um parâmetro de consulta do controlador, ele não se propaga para a URL. Posso verificar o valor da propriedade no controlador e está definido corretamente, mas a URL não mudou. Tentei usar um Ember.run.next sem sucesso. Ai!

Enfrentando esse problema também

@rwjblue : Existe alguma atualização sobre isso?

Qualquer atualização? Aqui, mesmo ao alterar o valor do controlador, a url é atualizada por alguns ms e volta ao valor antigo, mesmo que o controlador tenha o novo valor na variável

Aqui está uma solução alternativa:

No controlador, adicione um observador que altere o parâmetro de consulta no próximo ciclo de execução após ter sido definido. Neste exemplo, eu queria remover o parâmetro de consulta token da URL e essa abordagem funciona bem.

import Ember from 'ember';

export default Ember.Controller.extend({
  queryParams: ['token'],

  token: null,

  unsetToken: Ember.observer('token', function() {
    if (this.get('token')) {
      Ember.run.next(this, function() {
        this.set('token', null);
      });
    }
  }),
});

Acabei de encontrar isso hoje, quando tentei definir um parâmetro de consulta do setupController na inicialização. run.next parece uma solução alternativa, mas acho que a solução adequada seria ter 2 rotas e, na inicialização, a primeira rota faria a segunda rota de transição para o valor do parâmetro de consulta.

Ember 2.8

Marcando o problema como inativo de acordo com nossa política de triagem .

Eu também estou vendo esse problema no Ember 2.11, tentar limpar um parâmetro de consulta no controlador não tem efeito. A solução alternativa de @barelyknown me leva a maior parte do caminho, mas ainda consideraria isso um bug aberto.

EDIT: Ignore todo esse jazz. Há algumas informações ruins / erradas aqui, e @locks me indicou uma solução muito melhor - com um parâmetro de consulta em vez de um segmento dinâmico - imediatamente abaixo. Ele vincula o parâmetro de consulta a uma propriedade normal com uma propriedade de sombra computada que limpa e define get (minhas tentativas anteriores envolveram vincular o parâmetro de consulta a uma propriedade computada que higienizou e configurou set ) . Desculpe pelo barulho!


A melhor solução ...

// app/router.js
Router.map(function() {
  this.route('shop');
});

// app/routes/shop.js
export default Ember.Route.extend({
  queryParams: {
    _selectedItemIndex: {
      replace: true
    }
  }
});

// app/controllers/shop.js
import computed from 'ember-macro-helpers/computed';

export default Ember.Controller.extend({
  cart: Ember.service.inject(),

  queryParams: {
    _selectedItemIndex: 'i'
  },

  _selectedItemIndex: 0,

  selectedItemIndex: computed('_selectedItemIndex', {
    get(index) {
      const itemsLength = this.get('cart.items.length');

      if (isNaN(index) || index < 0 || index >= itemsLength) {
        index = 0;
      }

      return this.set('_selectedItemIndex', index);
    },

    set(index) {
      return this.set('_selectedItemIndex', index);
    }
  })
});


O problema original e a solução ...

Perdi a maior parte de ontem para esse problema que ainda persiste na versão 2.14-beta. Meu caso de uso é higienizar um parâmetro de consulta para usar como índice em um Ember.Array. Se estiver malformado (por exemplo, NaN ou uma string) e / ou fora dos limites, ele deve usar um índice padrão e atualizar o URL para refletir o ajuste (para que os eventos em resposta a cliques futuros sejam acionados de forma adequada - posso explicar isso mais adiante para ajudar a demonstrar que este não é apenas um problema cosmético).

Não consigo definir a propriedade de setupController() pois ela não atualiza o URL (conforme descrito neste problema). Não posso defini-lo no próximo tick usando Ember.run porque isso terá efeito muito tarde (ou seja, um índice inválido já teria sido usado para acessar o array). Não posso defini-lo uma vez e, em seguida, defini-lo novamente no próximo tique para atualizar o URL porque não há nenhuma alteração de propriedade (ou pelo menos é o que eu suspeito que seja o motivo pelo qual não funciona).

Não posso usar uma propriedade computada com um setter de higienização no controlador porque você não pode vincular um parâmetro de consulta a uma propriedade computada. Não posso usar um observador em uma propriedade normal porque você não pode definir a propriedade que está observando. Não posso usar um observador com Ember.run devido ao problema descrito acima.

Não posso chamar this.transitionTo({ queryParams: .. }) de setupController() ou o gancho beforeModel() ou controller.transitionToRoute({ queryParams: .. }) de setupController() devido a # 14606 e problemas relacionados. Não posso definir refreshModel para true para o parâmetro de consulta porque outras coisas estão acontecendo no gancho model() que não deve ser repetido se esse parâmetro de consulta mudar.

É evidente que existe um nexo de dor aqui. Esse problema, o número 14606, e a limitação de não ser capaz de vincular um parâmetro de consulta a uma propriedade computada se combinam para criar uma armadilha simples e frustrante.

Esta é minha solução alternativa: criei uma rota "selecionar" aninhada que simplesmente pega o parâmetro de consulta (ou - como no código abaixo - um segmento dinâmico), limpa-o e define a propriedade em seu controlador pai. Se o índice higienizado estiver fora dos limites, ele fará a transição para a rota de índice aninhada, que por sua vez fará a transição de volta para a rota de seleção aninhada com o índice padrão. As rotas aninhadas não têm modelos ou controladores e a rota pai não tem saída; eles existem apenas para lidar com esse problema de roteamento.

// app/router.js
Router.map(function() {
  this.route('shop', function() {
    this.route('index', { path: '/' });
    this.route('select', { path: '/:index' });
  });
});

// app/routes/shop.js
export default Ember.Route.extend({
  setupController(controller, model) {
    this._super(...arguments);

    // some logic to set up the cart service
  },

  model() {
    // fetch products to shop
  }
});

// app/controllers/shop.js
export default Ember.Controller.extend({
  cart: Ember.service.inject(),

  selectedItemIndex: 0,

  actions: {
    selectItem(index) {
      return this.replaceRoute('shop.select', index);
    }
  }
});

// app/routes/shop/index.js
export default Ember.Route.extend({
  beforeModel() {
    return this.replaceWith('shop.select', 0);
  }
});

// app/routes/shop/select.js
export default Ember.Route.extend({
  setupController(_, { index }) {
    this._super(...arguments);

    const
      parentController = this.controllerFor('shop'),
      itemsLength = parentController.get('cart.items.length');

    index = parseInt(index, 10);
    if (Number.isNaN(index) || index < 0 || index >= itemsLength) {
      return this.replaceWith('shop.index');
    }

    parentController.set('selectedItemIndex', index);
  },

  model: _ => _
});

@mwpastore obrigado pela atualização, vamos encerrar isso. Tenha um ótimo fim de semana!

@locks se você quiser, reabra um problema de documentação para observar isso no setupController (veja as notas nos menus suspensos por

@mwpastore Parece que poderíamos continuar com uma postagem no fórum em https://discuss.emberjs.com/ com sua solução

Esperar até que esse problema seja resolvido com uma solução alternativa para contornar o bug que ele relata e essa solução envolve definir uma propriedade em um getter computado?

Estou curioso para saber se há atualizações sobre isso.

Estou usando Ember.run.next dentro da rota setupController

Esta página foi útil?
0 / 5 - 0 avaliações