Javascript-форум (https://javascript.ru/forum/)
-   ExtJS (https://javascript.ru/forum/extjs/)
-   -   Два связанных параметра в config-е класса (https://javascript.ru/forum/extjs/57164-dva-svyazannykh-parametra-v-config-e-klassa.html)

khusamov 22.07.2015 17:02

Два связанных параметра в config-е класса
 
В продолжение обсуждения конфигурационных свойств, который был начат в ветке http://javascript.ru/forum/extjs/570...mplyaru-2.html появился вопрос.

Как правильно написать методы update* у двух связанных параметров?

Их связь заключается в том, что изменив один из них, другой пересчитывается и наоборот.

Например есть класс Арка. Арку можно определить как через радиус арки, так и через высоту арки. Я пишу такой код:

Ext.define("Arc", {
	
	config: {
		
		height: 0,
		
		radius: 0
		
	},
	
	applyHeight: function(height) {
		this._radius = <расчет радиуса на основании высоты>;
		return height;
	},
	
	applyRadius: function(radius) {
		this._height = <расчет высоты на основании радиуса>;
		return radius;
	}
	
});


Тут мне приходится выкручиваться. Если я вызову this.setRadius() вместо присвоения this._radius = , то все зациклится. И чтобы не запустился apply* связанного параметра, приходится присваивать this._radius =.

Это какой-то недокументированный способ. Я просто подсмотрел, где хранятся конфиги. Оказалось что в переменных с префиксом подчеркивание.

А как правильно это сделать?

nohuhu 22.07.2015 21:43

Стандартных средств для таких случаев нет, поскольку они весьма редки. Я бы использовал простые флаги:

Ext.define('Arc', {
    config: {
        height: 0,
        radius: 0
    },

    applyHeight: function(newHeight) {
        var radius = <считаем радиус>;
        
        // Аксессоры конфигов вызываются в контексте объекта
        if (!this.disableHeightCalc) {
            this.disableRadiusCalc = true;
            this.setRadius(radius);
            this.disableRadiusCalc = false;
        };

        return newHeight;
    },

    applyRadius: function(newRadius) {
        var height = <считаем высоту>;
        
        if (!this.disableRadiusCalc) {
            this.disableHeightCalc = true;
            this.setHeight(height);
            this.disableHeightCalc = false;
        };

        return newRadius;
    },

    constructor: function(cfg) {
        // Мы доверяем входным конфигам, их не надо пересчитывать
        this.disableHeightCalc = this.disableRadiusCalc = true;
        this.initConfig(cfg);
        this.disableHeightCalc = this.disableRadiusCalc = false;
    }
});


Что касается префикса для конфигурационных свойств, то насколько я понимаю, это была такая (тщетная) попытка удержать пользователей от изменения конфигов напрямую, в обход аксессоров. Security by obscurity конечно же не работает, но префиксы оставили как есть для пущей совместимости с Sencha Touch, откуда была притащена система конфигов.

Для большинства классов Ext JS (Classic toolkit в 6) префиксы конфигурационных свойств выключены.

khusamov 23.07.2015 12:32

Это зачем?

// Мы доверяем входным конфигам, их не надо пересчитывать
this.disableHeightCalc = this.disableRadiusCalc = true;
this.initConfig(cfg);
this.disableHeightCalc = this.disableRadiusCalc = false;


На входе либо радиус либо высота и пересчитать второй параметр обязательно надо, так как getParam не выдаст верное значение того параметра, который не рассчитан.

Кстати, были какие-то неясные проблемы, когда при вызове this.initConfig(cfg) в одном из updateParam() вызывался setOtherParam()... вроде проблема была в том, что параметр не был еще инициализирован что-ли... а на него вызывался setParam()...

nohuhu 23.07.2015 21:43

Цитата:

Сообщение от khusamov (Сообщение 381088)
Это зачем?

На входе либо радиус либо высота и пересчитать второй параметр обязательно надо, так как getParam не выдаст верное значение того параметра, который не рассчитан.

Это для примера, конечно же. Вы знаете свой код, но я-то не знаю. :)

Цитата:

Кстати, были какие-то неясные проблемы, когда при вызове this.initConfig(cfg) в одном из updateParam() вызывался setOtherParam()... вроде проблема была в том, что параметр не был еще инициализирован что-ли... а на него вызывался setParam()...
Насколько я помню, конфигуратор должен такие коллизии обходить. Хотя если возникает круговая ссылка, когда конфиг foo хочет инициализировать конфиг bar, а тот в свою очередь хочет foo, тогда конечно это конечно проблема. Такую проблему можно обойти, отключив механизм взаимных инициализаций перед initConfig, как показано в моём примере; когда конфиг уже готов, можно вызвать setFoo ещё раз.


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