Объедините linkTo и помощников действий в Ember.js

Мне нужно объединить linkTo и помощников действий в Ember.js. Мой код:

{{#link-to 'index'}}<span {{action 'clear'}}>Clear</span>{{/link-to}}

Но я хотел бы сделать это примерно так:

{{#link-to 'index' {{action 'clear'}} }}Clear{{/link-to}}

А также:

<li>
    {{#link-to 'support'}}
        <span {{action 'myAction' 'support'}}>Support</span>
    {{/link-to}}
</li>

Для того, чтобы:

<li>
    {{#link-to 'support' {{action 'myAction' 'support'}} }}Support{{/link-to}}
</li>

Как мне этого добиться?

Решение

Проверьте мой ответ на совместимость с Ember 2.0, хорошо для решения SEO.

9 ответов

Решение

Ember Link Action addon

Недавно я разработал этот аддон, чтобы решить эту проблему с помощью стиля, совместимого с Ember 2.0 - 2.14+ (1.13 также работает!), И использовать преимущества закрывающих действий / имен действий. Это нормально для SEO!

Установить аддон

ember install ember-link-action

использование

Вы можете передать закрывающее действие как invokeAction парам к {{link-to}} составная часть:

{{#link-to 'other-route' invokeAction=(action 'testAction')}}
  Link to another route
{{/link-to}}

Вы также можете использовать имя действия вместо действия закрытия:

{{#link-to 'other-route' invokeAction='testAction'}}
  Link to another route
{{/link-to}}

Для передачи параметров в действие вы можете использовать:

{{#link-to 'other-route' invokeAction=(action 'testAction' param1 param2)}}
  Link to another route
{{/link-to}}

Совместимость

Автоматизированный набор тестов подтверждает, что аддон работает с 1.13 до последних выпусков Ember 3.

Работает с выпуском, бета и канареек Ember.

Аддон GitHub хранилище. Вклад приветствуется.

Обновление: см. Комментарий Майкла Ланга ниже для Ember 1.8.1+

Проблема с ответом Мыслика (не используется link-to на всех, но вместо этого с помощью action а потом transitionToRoute) это то, что это бесполезно для SEO, боты поисковых систем ничего не увидят.

Если вы хотите, чтобы то, на что указывает ваша ссылка, было проиндексировано, проще всего иметь старый добрый <a href=x> там. Лучше всего использовать link-to так что ваши URL ссылки синхронизируются с вашими URL маршрута. Решение, которое я использую, дает как действие для выполнения работы, так и удобное link-to индексировать страницы.

Я переопределяю некоторые функции Ember.LinkView:

Ember.LinkView.reopen({
  action: null,
  _invoke: function(event){
    var action = this.get('action');
    if(action) {
      // There was an action specified (in handlebars) so take custom action
      event.preventDefault(); // prevent the browser from following the link as normal
      if (this.bubbles === false) { event.stopPropagation(); }

      // trigger the action on the controller
      this.get('controller').send(action, this.get('actionParam'));
      return false; 
    }           

    // no action to take, handle the link-to normally
    return this._super(event);
  }
});

Затем я могу указать, какое действие предпринять и что передать в Handlebars:

<span {{action 'view' this}}>
  {{#link-to 'post' action='view' actionParam=this}}
    Post Title: {{title}}
  {{/link-to}}
</span>

В контроллере:

App.PostsIndexController = Ember.ArrayController.extend({
  actions: {
    view: function(post){
      this.transitionToRoute('post', post);
    }
  }
}

Таким образом, когда я кеширую отрендеренную копию страницы и передаю ее индексирующему боту, он увидит реальную ссылку с URL и проследит за ней.

(обратите внимание также, что transitionTo в настоящее время устарела в пользу transitionToRoute)

Ни одна из этих комбинаций не будет работать в Ember.js, но вам не нужно объединять эти два помощника. Почему бы вам просто не использовать хелпер действий и позволить ему переходить к контроллеру или маршруту? Там вы можете использовать transitionToRoute в контроллере или transitionTo в пути.

Например, в контроллере вы можете иметь такой код:

App.PostsController = Ember.ArrayController.extend({
    clear: function () {
        // implement your action here
        this.transitionToRoute('index');
    }
});

Это прекрасно работает в 1.6.0-бета.5:

<span {{action "someAction"}}>
  {{#link-to "some.route"}}
    Click Me
  {{/link-to}}
</span>

Ссылка произойдет, и затем щелчок всплывет до обработчика действия. Это задокументировано (хотя и косвенно) здесь.

Изменить: исправлен синтаксис при открытии тега ссылки

Мне нравится подход Cereal Killer за его простоту, но, к сожалению, для меня это проблема. Когда браузер переходит на другой маршрут, он перезапускает приложение Ember.

Начиная с Ember 2.6, используется следующий простой подход:

<span {{action 'closeNavigationMenu'}}> {{#link-to 'home' preventDefault=false}} Go Home {{/link-to}} </span>

Это обеспечивает следующее:

  • перемещается по маршруту "домой"
  • вызывается действие 'closeNavigationMenu'
  • при наведении курсора в браузере отображается ссылка, по которой будет следовать (для SEO и лучшего UX)
  • навигация в браузере не приводит к перезагрузке приложения Ember

Имея ту же проблему, я нашел это простое решение:

{{#linkTo eng.rent class="external-button"}}<div class="internal-button" {{action "updateLangPath"}} >X</div>{{/linkTo}}

затем, управляя внешней кнопкой и внутренней кнопкой классов CSS в таблице стилей, я убедился, что "внутренняя кнопка" покрывает всю область "внешней кнопки"; таким образом невозможно нажать на внешнюю кнопку, не нажимая на внутреннюю кнопку.

Это хорошо работает для меня; надеюсь, что это может помочь...

Вот как я решил эту проблему в нашем демонстрационном приложении для книги O'Reilly Ember.js: https://github.com/emberjsbook.

Вы можете увидеть полный источник здесь: https://github.com/emberjsbook/rocknrollcall

По мнению:

{{#if artistsIsChecked}}
  {{#if artists.length}}
    <h3>Artists</h3>

    <ul class="search-results artists">
      {{#each artists}}
        <li><a {{action 'viewedArtist' this.enid }}>{{name}}</a></li>
      {{/each}}
    </ul>
  {{/if}}
{{/if}}

И контроллер:

App.SearchResultsController = Em.ObjectController.extend({
  actions: {
    viewedArtist: function(enid) {
      this.transitionToRoute('artist', enid);
    },
    viewedSong: function(sid) {
      this.transitionToRoute('song', sid);
    }
  },
  needs: ['artists', 'songs'],
  artistsIsChecked: true,
  songsIsChecked: true,
  artists: [],
  songs: []
});

Вот как это будет выглядеть после Ember 3.11.0 с on модификатор.

      <LinkTo
  {{on "click" this.recordMetrics}}
  @route="post.see-all"
  @model={{@model}}
  @bubbles={{false}}>
  Link Me
</LinkTo>

bubblesпоказан только для иллюстрации LinkTo API.

https://blog.emberjs.com/ember-3-11-released/

Теги ссылки на Ember используют маршруты для открытия новых представлений, поэтому вы можете выполнять любые функции, которые хотите добавить в атрибут действия action ссылки в setupController метод целевого маршрута вместо действия контроллера.

Смотрите здесь в руководстве Ember: http://emberjs.com/guides/routing/setting-up-a-controller/

Это работает только в том случае, если вы хотите выполнять действие при каждом доступе к маршруту, в отличие от конкретных ссылок.

Не забудьте включить controller.set('model', model); линия вместе с тем, что вы положили туда.

Другие вопросы по тегам