Extjs: как подойти к концепции: добавить, удалить, добавить экземпляр

Концепция. Рассмотрите возможность использования двух панелей A и B и окна C, как в следующем примере. Кнопки на окне переключаются между двумя панелями.

var A = new Ext.Panel({
    title: 'A'
});

var B = new Ext.Panel({
    title: 'B'
});

var C = new Ext.Window({
    layout: 'fit',
    width: 300,
    height: 300,
    items: A,
    buttons: [
    {
        text: 'Switch to A',
        handler: function() {
            C.removeAll(false);
            C.add(A);
            C.doLayout();
        }
    }, {
        text: 'Switch to B',
        handler: function() {
            C.removeAll(false);
            C.add(B);
            C.doLayout();
        }
    }]
});
C.show();

Концепция очень проста: добавьте компонент, удалите его и снова добавьте тот же экземпляр.

Проблема: переключение с A на B работает, а возврат к A — нет (B остается, а A больше не отображается).

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

Я понимаю, что могут быть разные случаи при рассмотрении FormPanel по сравнению с другими макетами/компонентами, но должен быть общий и правильный способ сделать это :)


person Chau    schedule 31.03.2011    source источник


Ответы (2)


Возможно, макет card — это именно то, что вам нужно:

var C = new Ext.Window({
    layout: 'card',
    width: 300,
    height: 300,
    activeItem: 0,
    items: [A, B],
    buttons: [{
        text: 'Switch to A',
        handler: function() {
            C.getLayout().setActiveItem(0);
        }
    }, {
        text: 'Switch to B',
        handler: function() {
            C.getLayout().setActiveItem(1);
        }
    }]
});
C.show();

Я предполагаю, что проблема с вашим кодом заключается в том, что вы снова используете один и тот же экземпляр. Ext внутренне устанавливает флаг rendered для компонента после его записи в дерево DOM. Поскольку флаг rendered остается истинным после того, как вы удалили компонент из C, он не будет перерисовываться при повторном добавлении компонента.

Простое изменение заставит ваш код работать: добавьте A.rendered = false; и B.rendered = false соответственно перед вызовом C.doLayout() в обработчиках кнопок.

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

person Stefan Gehrig    schedule 31.03.2011
comment
@Stefan: Это визуально может решить проблему с панелью, но я думаю в более общем плане. Как насчет того, чтобы иметь набор элементов управления формой и в одной ситуации показывать один их подмножество, а в другой ситуации показывать другой подмножество, при этом все время сохраняя начальные экземпляры компонентов. Есть ли в этом смысл? Вместо создания экземпляра нового элемента управления, когда он мне нужен, я хочу поддерживать конечный набор элементов управления. Концептуально похоже на TabPanel, но без вкладок над ним. - person Chau; 31.03.2011
comment
Но почему это мешает раскладке card? Если вам не нравится числовое назначение, вы также можете использовать ids или itemIds для обращения к activeItem или активируемому элементу. - person Stefan Gehrig; 31.03.2011
comment
Одно другому не мешает. Макет card просто не то, что я ищу. Бывший. Я не могу показывать два товара одновременно. Мой пример в OP был самым простым, который я мог придумать. Я хочу иметь возможность иметь набор компонентов и одновременно отображать один или несколько из них, а когда пользователь что-то делает, я хочу иметь возможность показывать/скрывать/изменять порядок появления компонентов в моем установлен. X.rendered = false - разве это не мешает состоянию компонента неудобным образом, что снова требует от меня поддержки других атрибутов? - person Chau; 31.03.2011
comment
X.rendered = false наверняка оставит ваши компоненты в грязном состоянии, что может привести к очень сложным проблемам. Не то, что вы должны использовать в своем коде. Это было просто, чтобы показать, в чем проблема на самом деле. - person Stefan Gehrig; 31.03.2011
comment
ОК - теперь я вижу вашу проблему. Но я не думаю, что компоненты предназначены для этого требования, поскольку они связывают логический компонент с отображаемым деревом DOM. Другой вариант — скрыть все компоненты и сделать видимыми только те, которые требуются в данный момент. - person Stefan Gehrig; 31.03.2011
comment
Да, я думал об этом. Но тогда я не уверен, как браузер справится с любыми изменениями в порядке появления: S - person Chau; 31.03.2011
comment
Вам придется вызывать doLayout() после каждого изменения видимости, чтобы Ext пересчитывал макет и соответствующий размер компонентов, но в целом это будет работать. Однако не уверен, как браузеры будут обрабатывать большое количество компонентов. - person Stefan Gehrig; 31.03.2011
comment
Спасибо за все ваши комментарии и соображения. Я попытаюсь представить структуру своих компонентов по-другому, избегая повторного использования компонентов. - person Chau; 01.04.2011

Я нашел простое решение, но это скорее хак. После удаления компонента (вашей панели A или B) вы должны добавить его в другой контейнер, который должен отображаться. Вот пример, в котором панели перемещаются в скрытый контейнер:

var A = new Ext.Panel({
    title: 'A'
});

var B = new Ext.Panel({
    title: 'B'
});

var C = new Ext.Window({
    layout: 'fit',
    width: 300,
    height: 300,
    items: A,
    buttons: [
    {
        text: 'Switch to A',
        handler: function() {
            C.remove(B, false);
            T.add(B);
            C.add(A);
            C.doLayout();
        }
    }, {
        text: 'Switch to B',
        handler: function() {
            C.remove(A, false);
            T.add(A);
            C.add(B);
            C.doLayout();
        }
    }]
});

var T = new Ext.Container({
    renderTo: "temporaryContainer",
    renderHidden: true
});

C.show();

И где-то в теле страницы вам нужно иметь это:

<div id="temporaryContainer" class="x-hidden"></div>

Протестировано с ExtJs 4.0.2a.

person liviucmg    schedule 31.07.2011