Javascript / ExtJS: «Условное наследование»? - PullRequest
0 голосов
/ 25 декабря 2009

Мы используем ExtJS для веб-приложения. В этом приложении мы используем стандартный элемент управления Ext.form.ComboBox, когда требуется простое раскрывающееся меню, и элемент управления Ext.us.Andrie.Select, когда нам требуется раскрывающееся меню, в котором можно выбрать несколько значений и / или очистить значение. Создание любого из них всегда требует набора шаблонного кода для параметров конфигурации, поэтому я хотел, чтобы класс, который сокращал шаблонный код, и пока я занимался этим, я хотел, чтобы этот класс мог генерировать либо простой выпадающий список, либо более продвинутый один, в зависимости от опции конфигурации (multi: true или clearable: true), но это оказалось намного сложнее, чем ожидалось.

Это самый близкий к мне рабочий результат:

MyComboBox = (function() {

    var singleDefaults = {
        typeAhead: false,
        triggerAction: 'all',
        selectOnFocus: false,
        allowBlank: true,
        editable: false,
        delay: 700
    };

    var multiDefaults = {
        typeAhead: false,
        triggerAction: 'all',
        selectOnFocus: false,
        allowBlank: true,
        editable: false,
        delay: 700
    };

    var constructor = function(config) {

            if (config.multi || config.clearable) {
                config = Ext.apply(this, config, multiDefaults);
                Ext.apply(this, Ext.ux.Andrie.Select.prototype);
                Ext.apply(this, Ext.ux.Andrie.Select(config));
                Ext.ux.Andrie.Select.prototype.constructor.call(this, config);
            } else {
                config = Ext.apply(this, config, singleDefaults);
                Ext.apply(this, Ext.form.ComboBox.prototype);
                Ext.apply(this, Ext.form.ComboBox(config));
                Ext.form.ComboBox.prototype.constructor.call(this, config);
            }
    };

    return function(config) {
        this.constructor = constructor;
        this.constructor(config);
    };

})();

Ну, это не сбой , но на самом деле это тоже не работает. Когда он настроен на поведение, подобное Ext.ux.Andrie.Select, он хочет загрузить хранилище, даже когда он загружен, не раскрывает раскрывающийся список, пока вы не начнете вводить данные в поле.

Еще один подход, который был опробован, был что-то вроде:

MyComboBox = Ext.extend(Ext.form.ComboBox, {
 constructor: function(config){
   if (config.multi || config.clearable) {
     Ext.form.ComboBox.prototype.constructor.call(this, config);
   } else {
     Ext.ux.Andrie.Select.prototype.constructor.call(this, config);
   }
 }
});

Это не работает, потому что выпадающий список Andrie не определяет собственную функцию constructor, поэтому он в конечном итоге вызывает функцию-конструктор Ext.form.ComboBox, от которой он наследует, что приводит к нормальному выпадающему списку, а не выпадающий список

Полагаю, это специфично для ExtJS, но если у вас есть подход, не зависящий от фреймворка, я могу перевести его на ExtJS.

Ответы [ 2 ]

3 голосов
/ 25 декабря 2009

При создании средне- и крупномасштабных приложений JavaScript я считаю удобным перенести создание / создание всех элементов управления в один класс, где каждый метод является фабрикой для этого элемента управления (т. Е. Поле со списком, текстовая область, кнопки, подсказки, флажки и т. д.). Поскольку только ваш фабричный класс обладает знаниями о том, как создавать элементы управления, это дает дополнительное преимущество, заключающееся в том, чтобы отделить логику вашего представления от самих экземпляров элементов управления (то есть, конечно, до тех пор, пока конструкторы и интерфейсы элементов управления остаются неизменными).

WidgetFactory = {
    comboBox: function(config) {
        return config.multi || config.clearable
            ? this.comboBoxMultiple(config)
            : this.comboBoxSingle(config)
    },

    comboBoxSingle: function(config) {
        // ... boiler plate goes here ...
    },

    comboBoxMultiple: function(config) {
        // ... boiler plate goes here ...
    },

    textArea    : function(config) {},
    textBox     : function(config) {},
    checkbox    : function(config) {},
    radioButton : function(config) {},
    button      : function(config) {},
    slider      : function(config) {},
    colorPicker : function(config) {}

    // etc
};

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


Редактировать:
Я не хотел подразумевать, что это заменит использование объектов для создания / создания элементов управления, а скорее будет использоваться в дополнение к . Использование WidgetFactory в качестве единого шлюза для всех элементов управления обеспечивает большую гибкость, чем просто возможность менять суперклассы. Вы можете поменять весь класс, не изменяя исходный класс, что позволит вам иметь несколько различных реализаций, если это необходимо.

Например, если ваше единственное поле со списком определено некоторым классом, namespace.ui.combobox.single, тогда вы можете сделать

comboBoxSingle: function(config) {
    return new namespace.ui.combobox.single(config);
},

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

comboBoxSingle: function(config) {
    return new namespace.ui.combobox.single2(config);
},

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

0 голосов
/ 02 января 2010

Почти забыл об этом вопросе. Я решил это, и если кому-то интересно, вот как это сделать:

var constructor = function(config) {
    if (config && (config.multi || config.clearable)) {
        config = Ext.apply(this, config, multiDefaults);
        Ext.applyIf(this, Ext.ux.Andrie.Select.prototype);
        Ext.ux.Andrie.Select.createDelegate(this)(config);
    } else {
        config = Ext.apply(this, config, singleDefaults);
        Ext.applyIf(this, Ext.form.ComboBox.prototype);
        Ext.form.ComboBox.createDelegate(this)(config);
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...