Как использовать Routing в Ext JS 5

Автор оригинала: Mitchell Simoens
  • Перевод
  • Tutorial

Маршрутизация — новая функция в Ext JS 5, которая позволяет связывать историю навигации с контроллером. Кнопки «Назад/Вперёд» — одна из основных частей интерфейса браузеров и с Ext JS 5 сделать навигацию в одностраничных приложениях стало очень просто.

Routing в Ext JS 5


Ext JS всегда позволял обрабатывать историю навигации при помощи класса Ext.util.History, но в Ext JS 5 мы сделали этот процесс ещё проще и гибче. Роутер предоставляет простую конфигурацию связи хэш-токенов и методов контроллера с поддержкой параметров и контролем выполнения маршрута (за кулисами используется Ext.util.History). Посмотрим на простой пример:

    Ext.define('MyApp.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'home' : 'onHome'
        },
 
        onHome : function() {}
    });


В объекте routes ключ home — это хэш, а onHome — метод в контроллере, который выполняется при переходе по нему (например: localhost#home). Чтобы изменить хэш внутри котнроллера, можно использовать метод redirectTo:

 this.redirectTo(‘home’); //редиректит на http://localhost#home

Это изменит хэш URL на #home, что в свою очередь вызовет метод onHome, где контекстом будет экземпляр контроллера MyApp.controller.Main, в котором был определён маршрут. Если у вас в нескольких контроллерах прописан одинаковый маршрут, то очерёдность выполнения будет такой, в какой прописаны контроллеры приложения (массив controllers).

Хэш-токены и параметры


Хэш-токен может содержать параметры, а роутер передаёт их в методы контроллера как аргументы. Хэш может выглядеть как '#user/1234', где 1234 — ID пользователя. Чтобы совпадать с таким хэшем, контроллер конфигурируется следующим образом:

    Ext.define(‘MyApp.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'user/:id' : 'onUser'
        },
 
        onUser : function(id) {}
    });

При конфигурации маршрута с параметрами перед именем параметра ставится двоеточие. В данном случае это :id. Роутер возьмёт любое переданное значение и передаст его в метод onUser. Порядок аргументов, передаваемых в метод, совпадает с порядком параметров, определённом в маршруте.

Вы можете контроллировать совпадение параметров хэша, используя регулярные выражения. В примере выше ID может содержать только числа, а остальные значения совпадать не должны. Для этого используется конфиг conditions:

    Ext.define('Fiddle.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'user/:id' : {
                action     : 'onUser',
                conditions : {
                    ':id' : '([0-9]+)'
                }
            }
        },
 
        onUser : function(id) {}
    });

Этот пример показывает две вещи: маршрут может быть объектом, в котором ключ action — метод контроллера, а conditions — объект с параметрами и строками регулярных выражений. Причина, по которой регулярное выражение записывается в строке в том, что роутер создаёт основное выражение, основываясь на параметрах маршрута. Конфиг conditions позволяет переопределить регулярные выражения по умолчанию. Регулярное выражение по умолчанию для строковых параметров — '([%a-zA-Z0-9\\-\\_\\s,]+)'.

Чтобы обработать переход по маршруту, для которого нет совпадений, существует событие unmatchedroute. Его обработчик можно повесить как на приложение, так и на контроллер. Например, на контроллер:

    Ext.define('Fiddle.controller.Main', {
        extend : 'Ext.app.Controller',
 
        listen : {
            controller : {
                '*' : {
                    unmatchedroute : 'onUnmatchedRoute'
                }
            }
        },
 
        onUnmatchedRoute : function(hash) {}
    });

Иногда бывает нужно отловить переход по маршруту, чтобы прекратить его выполнение или продолжить после выполнения какого-нибудь асинхронного действия, например, ajax-запроса. Для этого в маршруте используется ключ before. Вот пример, в котором выполнение маршрута продолжается после ajax-запроса:

    Ext.define('Fiddle.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'user/:id' : {
                action     : 'onUser',
                before     : 'beforeUser',
                conditions : {
                    ':id' : '([0-9]+)'
                }
            }
        },
 
        beforeUser : function(id, action) {
            Ext.Ajax.request({
                url     : '/user/confirm',
                params  : {
                    userid : id
                },
                success : function() {
                    action.resume();
                },
                failure : function() {
                    action.stop();
                }
            });
        },
 
        onUser : function(id) {}
    });

В методе beforeUser принимается аргумент id по аналогии с onUser, а также — action, в котором есть методы resume и stop, контроллирующие выполнение маршрута. Метод action.resume() продолжит маршрут, позволяя делать его асинхронным, а action.stop() — предотвратит его выполнение. Если в метод stop передать аргумент true, то выполнение всех маршрутов будет остановлено.

Приложения Ext JS становятся больше и сложнее, и они могут требовать обработки нескольких хэш-токенов одновременно. В Ext JS 5 эта возможность реализована, при этом, каждый хэш-токен обрабатывается отдельно в своей песочнице. Это означает, что если вы отменяете один маршрут, передавая true в метод action.stop, это отменит маршруты только по этому хэш-токену, а остальные продолжат выполнение. Каждый токен должен быть разделён вертикальной линией:

    #user/1234|message/5ga

Роутер разделит хэш и получит токены 'user/1234' и 'message/5ga'. Первым он обработает токен user, найдёт все маршруты, совпадающие с ним и выполнит их. Если не будет найдено ни одного маршрута, совпадающего с этим токеном, вызовется событие unmatchedroute. Затем роутер перейдёт к токену message и по аналогии найдёт связанные маршруты. Если не найдёт, вызовется событие unmatchedroute.

Заключение


Новый роутер в ExtJS 5 легко настраивается и позволяет также легко обрабатывать историю браузера, при этом он остаётся гибким и мощным, чтобы соотвествтовать требованиям сложных приложений. Вместе с MVC+VM, двунаправленным дата-биндингом и другими новыми функциями, Ext JS 5 — прекрасный фреймворк для корпоративных приложений.
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 5

    0
    А есть ли возможность из определенного роута передать управление в другой контролер? к примеру отдать оставшуюся часть токена поcле #user/ котроллеру User на разбор?
      0
      Судя по описанию, управление автоматически передаётся от контроллера к контроллеру в порядке их определения в Ext.application. А для чего такая задача?
        0
        К примеру у меня есть универсальный абстрактный модуль для редактирования и просмотра разных записей, для юзеров это #/users/, #/users/:id, #/users/:id/something, так же и для мест #/places/:id, #/places/:id и т.д.
        В идеале я вижу что первую часть обрабатывает роутинг контролер, который решает в какую реализацию этого модуля передать управление(users, places...), а дальше уже контролер этого модуля разруливает что делать. Вложенность может быть какой угодно, можно писать универсальные реализации, по типу как в django.
          0
          Ну да, у вас те же мысли, что и в комментариях к оригинальной статье. Там рекомендуют использовать разделение токенов: #user/1234|messages. Но у себя в проекте я по-другому делал (ещё давно прикручивал routing из Sencha Touch, там разделения не было):

          Ext.define('MyController', {
            extend: 'Ext.app.Controller',
            
            routes: {
              'users': 'userList',
              'users/:id': 'userDetails',
              'users/:id/something': 'somethingForUser'
            },
            
            userList: function () {
              this.showUserList();
            },
              
            userDetails: function(id) {
              this.userList();
              this.showUserDetails(id);
            },
            
            somethingForUser: function (id) {
              this.userDetails(id);
              this.doSomethingForUser(id);
            }
          });
          


          UPD. А если сильно хочется использовать routing контроллер, то я бы делал это на событиях. Роутинг сгенерил, а остальные подписаны.
            0
            ну да, примерно так я и делаю, только внутри viewcontroller каждый свое обрабатывает (сейчас как раз поднимаю новый проект на extjs 5). По мне это эстетически некрасиво когда названия роутов из вью-контролера меню дублируются в вью-контроллере для конкретных действий. =)

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое