Javascript-форум (https://javascript.ru/forum/)
-   Angular.js (https://javascript.ru/forum/angular/)
-   -   Двусторонняя связь location param и model (https://javascript.ru/forum/angular/50651-dvustoronnyaya-svyaz-location-param-i-model.html)

Sufir 06.10.2014 11:25

Двусторонняя связь location param и model
 
Мне нужно сделать своего рода тройной биндинг, т.е. изменение модели должно отражаться на адресной строке и наоборот, изменение параметра в строке должно менять модель. Что бы формировалась ссылка для текущего состояния фильтра, которой можно будет поделиться.

Я решил довольно костыльным методом:
$scope.$watch('selectedStaff', function () {
    var currentStaffId = ($scope.selectedStaff) ? $scope.selectedStaff.id : 0;

    if ($scope.selectedStaff !== undefined /*&& $scope.selectedStaff !== null*/) {
        $location.search('fStaffId', (currentStaffId) ? currentStaffId : null);
        /* Тут обновление данных... */
    }

});
$scope.$on('$routeUpdate', function () {

        var currentStaffId = parseInt($routeParams.fStaffId);
        if (currentStaffId > 0 && $scope.staffList.length > 0) {
            for (var k in $scope.staffList) {

                    if ($scope.staffList[k]['id'] === currentStaffId) {
                        $scope.selectedStaff = $scope.staffList[k];
                        break;
                    }

            }
        }

});


Но работает это довольно криво, то сбрасывается параметр в адресной строке (т.к. $watch сначала дважды вызывается со значениями null и undefined), приводит к лишним запросам к серверу, не обновляется селект... В общем, проблемный вариант.
Больше я пока ничего придумать не смог, опыта очень мало. Может подскажете как это правильно реализовать?

a.malitsky 09.10.2014 23:52

$location.search - я так же делаю. Еще сравниваю с default значениями чтобы все подряд в строку не пихать.

Чтобы watch не срабатывал изначально, поставь проверку newVal !== prevVal.

Я обновляю url сам, то есть не через watch, а когда что-то серьезно изменилось в состоянии app (в моем случае таких функций немного).

Про обращения на сервер и селект не понял.

Sufir 10.10.2014 16:09

Цитата:

Сообщение от a.malitsky (Сообщение 334545)
Чтобы watch не срабатывал изначально, поставь проверку newVal !== prevVal.

Я обновляю url сам, то есть не через watch, а когда что-то серьезно изменилось в состоянии app (в моем случае таких функций немного).

Примерно так и настроил, в общем-то работает, но как-то всё равно мне не очень нравится результат.

У меня список объектов на странице, и целый ряд всевозможных фильтров для него, при изменении значений которых должен и список меняться, соответсвенно.

Цитата:

Сообщение от a.malitsky (Сообщение 334545)
Про обращения на сервер и селект не понял.

Ну, при изменении значения в селекте данные фильтруюутся, т.е. идёт запрос на сервер. Т.к. на данный момент 5 фильтров, то при открытии страницы 6 запросов серверу уходит. Ну, я сделал отложенную загрузку - первый раз гружу только когда все селекты уже готовы. Но из-за этого возникает другая проблема: пока ожидаем формирования всех селектов - старница пустая, получается долгая загрузка основных данных...

В общем кое-как я порешал и настроил, но как хорошо и правильно сделать пока не нашел.

a.malitsky 10.10.2014 21:14

При первой загрузке страницы фильтры можно же брать из строки или дефолтные, не вижу смысла ждать - шли один запрос сразу со всеми полученными (как значения) фильтрами. А ng-change на селектах пусть проверяет переменную вроде initialLoadIsActive.

MetaDriver 16.10.2014 08:52

Цитата:

Сообщение от Sufir (Сообщение 333676)
Мне нужно сделать своего рода тройной биндинг, т.е. изменение модели должно отражаться на адресной строке и наоборот, изменение параметра в строке должно менять модель.
...........

Но работает это довольно криво, то сбрасывается параметр в адресной строке (т.к. $watch сначала дважды вызывается со значениями null и undefined), приводит к лишним запросам к серверу, не обновляется селект... В общем, проблемный вариант.

Постановка задачи кривоватая - страдает ненужной избыточностью. Сделать, конечно можно и в такой постановке, но это довольно бессмысленно. Я бы поправил следующим образом:
  1. При начальной загрузке страницы значения фильтров брать из адресной строки, и как абсолютно верно заметил коллега a.malitsky - сразу же отправлять запрос на сервер.
  2. При редактировании селектов, изменения отображать в адресной строке односторонне. Обратный биндинг (адресная строка -> фильтры) в динамике (при уже открытой странице) совершенно избыточен и не нужен. Сложно представить умника, который будет редактировать строку поиска в гуглояндексе, редактируя адресную строку браузера (!! :blink:), в то время как перед носом вполне человекоориентированный инпут (в твоём случае - селекты).
С этими поправками всё резко упрощается и ты, я уверен, с этим легко справишься.

a.malitsky 16.10.2014 18:51

Цитата:

Сообщение от MetaDriver
С этими поправками всё резко упрощается

Вроде там ничего сложного нет. А перезагрузка страницы (через f5) часто требует сохранения app state. И для этого обойтись без изменения параметров с их последующим чтением не получится.

MetaDriver 16.10.2014 23:10

Цитата:

Сообщение от a.malitsky (Сообщение 336060)
Вроде там ничего сложного нет. А перезагрузка страницы (через f5) часто требует сохранения app state. И для этого обойтись без изменения параметров с их последующим чтением не получится.

как эта логика соотносится с необходимостью заполнять селекты из содержимого адресной строки динамически (во время ручного редактирования адресной строки) ?
и причём здесь f5? перезагрузка страницы (f5, ctrl-f5) эквивалентна начальной загрузке по содержимому адресной строки. вам нужно отображать в адресную строку изменения ваших селектов, никто не спорит с этим.
а вот зачем обратный биндинг?

я не говорю, что вам не нужно парсить адресную строку, я сказал только что это достаточно сделать однократно, при начальной загрузке (инициализации) страницы. динамически отслеживать нет никакой необходимости. ну это, конечно, если ваше начальство не считает иначе..... :)

a.malitsky 21.10.2014 05:37

если просто что-то ввести, то ничего не произойдет, если нажать enter, то отработает router если я не путаю и получится изначальная загрузка app из параметров адресной строки.

Проверять что там изменил пользователь в адресной строке без перезагрузки (enter) state конечно не стоит. Согласен.

MetaDriver 21.10.2014 17:30

Ну и ладушки.

Sufir 29.10.2014 15:34

Цитата:

Сообщение от MetaDriver (Сообщение 335901)
При начальной загрузке страницы значения фильтров брать из адресной строки, и как абсолютно верно заметил коллега a.malitsky - сразу же отправлять запрос на сервер.

Просто "ожидание" гарантирует правильные значения в фильтрах. Если есть, к примеру, для какого-то параметра заданный список значений. У пользователя может быть какая-то битая ссылка или старая из закладок или присланная другим пользователем. Да и вообще всё что угодно в строке оказаться может (или не оказаться).
Соответственно в любом случае по готовности фильтров данные нужно обновить. Хотя бы в случае обнаружения такового несоответствия.

Цитата:

Сообщение от MetaDriver (Сообщение 335901)
Обратный биндинг (адресная строка -> фильтры) в динамике (при уже открытой странице) совершенно избыточен и не нужен.

Пожалуй что так. Перепишу в день рефакторинга.


Часовой пояс GMT +3, время: 12:47.