Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiView: implement selectedIndex property update when selected item is hidden #28145

Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion packages/devextreme/js/__internal/ui/m_multi_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,45 @@ const MultiView = CollectionWidget.inherit({
this._initSwipeable();
},

_setVisibleSelectedItemIndices(indices) {
const items = this.option('items');
const startingIndex = this.option('selectedIndex');
const allHidden = items.every((item) => item?.visible === false);
let visibleIndex = indices.find((index) => items[index]?.visible) ?? null;

if (visibleIndex === null) {
const firstVisibleItemIndex = items.slice(startingIndex).findIndex((item) => (typeof item === 'object' && item !== null
? item.visible || !('visible' in item)
: true));

if (firstVisibleItemIndex !== -1 && !allHidden) {
visibleIndex = firstVisibleItemIndex + startingIndex;
} else if (!allHidden) {
for (let i = startingIndex; i >= 0; i--) {
if (items[i]?.visible || !('visible' in items[i])) {
visibleIndex = i;
break;
}
}
} else {
visibleIndex = 0;
}
}

this.selectItem(visibleIndex)
.fail(() => this._animateItemContainer(0, noop))
.done(() => this._postprocessSwipe({ swipedTabsIndex: visibleIndex }));
},

_initMarkup() {
this._deferredItems = [];

this.callBase();

const selectedItemIndices = this._getSelectedItemIndices();
this._setVisibleSelectedItemIndices(selectedItemIndices);
this._updateItemsVisibility(this.option('selectedIndex'));

this._updateItemsVisibility(selectedItemIndices[0]);
this._setElementAria();
this._setItemsAria();
},
Expand Down Expand Up @@ -513,6 +544,11 @@ const MultiView = CollectionWidget.inherit({
this.callBase();
},

_updateSelectedIndex() {
ksercs marked this conversation as resolved.
Show resolved Hide resolved
this._setVisibleSelectedItemIndices([this.option('selectedIndex')]);
this._updateItemsVisibility(this.option('selectedIndex'));
},

_optionChanged(args) {
const { value } = args;

Expand All @@ -529,10 +565,14 @@ const MultiView = CollectionWidget.inherit({
this._invalidate();
break;
case 'items':
this._updateSelectedIndex();
this._updateSwipeDisabledState();
this._findBoundaryIndices();
this.callBase(args);
break;
case 'selectedIndex':
this._updateSelectedIndex();
break;
default:
this.callBase(args);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1659,3 +1659,200 @@ QUnit.module('swipeable disabled state', () => {
assert.equal(multiView.option('swipeEnabled'), false, 'MultiView.swipeEnabled');
});
});

QUnit.module('selectedIndex vs item.visible', () => {
QUnit.test('selectedIndex should be updated to the next visible item if initially selected item is hidden', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: false },
{ text: '3', visible: true },
],
selectedIndex: 1
});
const instance = $multiView.dxMultiView('instance');

assert.strictEqual(instance.option('selectedIndex'), 2, 'selectedIndex is updated on proper index');
});

QUnit.test('selectedIndex should be updated to the next visible item if it is changed to a hidden item at runtime', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: false },
{ text: '3', visible: true },
]
});
const instance = $multiView.dxMultiView('instance');
instance.option('selectedIndex', 1);

assert.strictEqual(instance.option('selectedIndex'), 2, 'selectedIndex is updated on proper index');
});

QUnit.test('selectedIndex should be zero when all items are not visible', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: false },
{ text: '2', visible: false },
{ text: '3', visible: false },
]
});
const instance = $multiView.dxMultiView('instance');

assert.strictEqual(instance.option('selectedIndex'), 0, 'selectedIndex is updated on proper index');
});

QUnit.test('selectedIndex should be set to zero if all items became hidden at runtime', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: false },
{ text: '3', visible: true },
],
selectedIndex: 2
});
const instance = $multiView.dxMultiView('instance');
instance.option({
items: [
{ text: '1', visible: false },
{ text: '2', visible: false },
{ text: '3', visible: false },
]
});

assert.strictEqual(instance.option('selectedIndex'), 0, 'selectedIndex is updated on proper index');
});

QUnit.test('when hiding non-selected item before selectedIndex, selectedIndex should not change', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: true },
{ text: '3', visible: true },
],
selectedIndex: 2
});
const instance = $multiView.dxMultiView('instance');
instance.option('items[1].visible', false);

assert.strictEqual(instance.option('selectedIndex'), 2, 'selectedIndex is updated on proper index');
});

QUnit.test('when hiding selected item selectedIndex should be set to next visible item', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: true },
{ text: '3', visible: true },
],
selectedIndex: 1
});
const instance = $multiView.dxMultiView('instance');
instance.option('items[1].visible', false);

assert.strictEqual(instance.option('selectedIndex'), 2, 'selectedIndex is updated on proper index');
});

QUnit.test('when hiding selected item positioned in the end, next visible item to the left is selected', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: true },
{ text: '3', visible: true },
],
selectedIndex: 2
});
const instance = $multiView.dxMultiView('instance');
instance.option('items[2].visible', false);

assert.strictEqual(instance.option('selectedIndex'), 1, 'selectedIndex is updated on proper index');
});

QUnit.test('when showing previously invisible item before selectedIndex, selectedIndex should not change', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: false },
{ text: '3', visible: true },
],
selectedIndex: 2
});
const instance = $multiView.dxMultiView('instance');
instance.option('items[1].visible', true);

assert.strictEqual(instance.option('selectedIndex'), 2, 'selectedIndex is updated on proper index');
});

QUnit.test('when showing previously invisible item after selectedIndex, selectedIndex should not change', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: false },
{ text: '3', visible: true },
],
selectedIndex: 0
});
const instance = $multiView.dxMultiView('instance');
instance.option('items[1].visible', true);

assert.strictEqual(instance.option('selectedIndex'), 0, 'selectedIndex is updated on proper index');
});

QUnit.test('when hiding last visible item selectedIndex should return to 0 index', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: false },
{ text: '2', visible: false },
{ text: '3', visible: true },
],
selectedIndex: 2
});
const instance = $multiView.dxMultiView('instance');
instance.option('items[2].visible', false);

assert.strictEqual(instance.option('selectedIndex'), 0, 'selectedIndex is updated on proper index');
});

QUnit.test('next visible item should be selected if currently selected item is hidden and loop=true', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: false },
{ text: '2', visible: false },
{ text: '3', visible: true },
],
loop: true
});
const instance = $multiView.dxMultiView('instance');

assert.strictEqual(instance.option('selectedIndex'), 2, 'selectedIndex is updated on proper index');
ksercs marked this conversation as resolved.
Show resolved Hide resolved
});

QUnit.test('next visible item should be selected if currently selected item is hidden and loop=true | items=[{ visible: true }, { visible: false }], selectedIndex = 1', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: false }
],
selectedIndex: 1,
loop: true
});
const instance = $multiView.dxMultiView('instance');

assert.strictEqual(instance.option('selectedIndex'), 0, 'selectedIndex is updated on proper index');
});
ksercs marked this conversation as resolved.
Show resolved Hide resolved

QUnit.test('previous visible item should be selected if currently selected item is hidden and multiple hidden item is in between them | loop = true', function(assert) {
const $multiView = $('#multiView').dxMultiView({
items: [
{ text: '1', visible: true },
{ text: '2', visible: false },
{ text: '3', visible: false }
],
selectedIndex: 2,
loop: true
});
const instance = $multiView.dxMultiView('instance');

assert.strictEqual(instance.option('selectedIndex'), 0, 'selectedIndex is updated on proper index');
});
ksercs marked this conversation as resolved.
Show resolved Hide resolved
});
nikkithelegendarypokemonster marked this conversation as resolved.
Show resolved Hide resolved
Loading