Как реализовать сортировку данных по запросу в списке с помощью плагина nativescript-drop-down?

Я создаю простое приложение Nativescript со списком элементов на основе массива. У меня проблемы с пониманием наблюдаемого модуля / шаблона MVVM. Я использую nativescript-drop-down, чтобы предоставить список сортировки для сортировки данных в списке. Данные правильно сортируются при первом отображении страницы, однако не обновляются при изменении индекса.

Как обеспечить правильную передачу значения "selectedIndex" раскрывающегося списка в модель просмотра и соответствующее обновление списка?

Я пробовал сортировку на основе selectedIndex как в модели, так и с помощью функции dropDownSelectedIndexChanged.

main-page.ts

const mainPageModel = new MainPageModel();

export function navigatingTo(args: EventData) {
    const page = <Page>args.object;
    page.bindingContext = mainPageModel;
}

Я попытался установить эту функцию на главной странице, но она не будет обновлять список, если не уйду, а затем вернется на страницу:

export function dropDownSelectedIndexChanged(args: SelectedIndexChangedEventData) {
    if (args.newIndex == 0) {
        mainPageModel.dataItems.sort(function (a, b) {
            return a.name.localeCompare(b.name);
        });
    } else if (args.newIndex == 1) {
        mainPageModel.dataItems.sort(function (a, b) {
            return b.name.localeCompare(a.name);
        });
    }
}

main-view-model.ts

export class MainPageModel extends Observable {
    // Dropdown populating
    @ObservableProperty() dropdownItems: ObservableArray<any>;
    @ObservableProperty() selectedIndex: number;

    // Recipe templating
    @ObservableProperty() isBusy: boolean = true;
    @ObservableProperty() dataItems: ObservableArray<any>;

    constructor() {
        super();
        this.isBusy = true;
        this.dataItems = new ObservableArray<any>();

        this.dropdownItems = new ObservableArray<any>();
        this.selectedIndex = 0;

        // Populate sort by dropdown
        const items = ["Name (A-Z)", "Name (Z-A)"];
        this.dropdownItems.push(items);

        // Populate recipes stored locally
        let storedRecipes = [];
        try {
            storedRecipes = appSettings.getAllKeys();
            storedRecipes.forEach(element => {
           this.dataItems.push(JSON.parse(appSettings.getString(element)))
            });
        } catch (e) {
            console.log("No stored recipes")
        }

        // Populate recipes from placeholder data
        getData().then((recipeData) => {
            this.dataItems.push(recipeData);
            this.isBusy = false;

            // Sort recipes by index
            // Done as an alternative to "dropDownSelectedIndexChanged"
            if (this.selectedIndex == 0) {
                this.dataItems.sort(function (a, b) {
                    return a.name.localeCompare(b.name);
                });
            } else if (this.selectedIndex == 1) {
                this.dataItems.sort(function (a, b) {
                    return b.name.localeCompare(a.name);
                });
            }
        });
    }
}

main-page.xml

    <GridLayout columns="*,auto,auto" rows="auto,5*" >
        <!-- Add &#xf2e7; back to button -->
        <Button horizontalAlignment="left" row="0" col="0" text="Add New Recipe" tap="addRecipe" class="add-button" />
        <Label horizontalAlignment="right" verticalAlignment="center" text="Sort by:" col="1" row="0" padding="10" fontWeight="bold" fontSize="18" />
        <dd:DropDown items="{{ dropdownItems }}" selectedIndex="{{ selectedIndex }}" 
                    opened="dropDownOpened" closed="dropDownClosed" 
                    selectedIndexChanged="dropDownSelectedIndexChanged"
                    row="0" col="2" itemsPadding="8" verticalAlignment="center" itemsTextAlignment="center" horizontalAlignment="right" />

        <ListView row="1" colSpan="3" class="list-group" items="{{ dataItems }}" separatorColor="transparent">
            <ListView.itemTemplate>
                <GridLayout recipeData="{{ $value }}" tap="recipeDetail" route="recipe-detail/recipe-detail" rows="*,auto,auto" columns="5*, *" class="list-group-item">
                    <Label row="0" col="0" text="{{ name }}" class="h2" />
                    <Image horizontalAlignment="center" row="0" rowSpan="2" col="2" src="{{ image }}" />
                </GridLayout>
            </ListView.itemTemplate>
        </ListView>
        <ActivityIndicator row="1" colSpan="3" busy="{{ isBusy }}" class="activity-indicator" />
    </GridLayout>

Хотя сортировка работает при начальной загрузке страницы, если логика находится в модели просмотра, она не меняется, если я выбираю другой индекс. В качестве альтернативы, если я попытаюсь изменить значение «selectedIndex» с помощью функции «dropDownSelectedIndexChanged», список не сортируется сразу, а обновится только после перехода назад и обратно на главную страницу.


person Elocnatsirt    schedule 21.10.2019    source источник


Ответы (1)


sort(...) метод не уведомляет компонент об изменении, в отличие от других методов (slice, pop, push). Попробуйте обновить ListView после сортировки,

export function dropDownSelectedIndexChanged(args: SelectedIndexChangedEventData) {
    if (args.newIndex == 0) {
        mainPageModel.dataItems.sort(function (a, b) {
            return a.name.localeCompare(b.name);
        });
    } else if (args.newIndex == 1) {
        mainPageModel.dataItems.sort(function (a, b) {
            return b.name.localeCompare(a.name);
        });
    }
   (<any>event.object).page.getViewById('YourListViewId').refresh();
}
person Manoj    schedule 21.10.2019
comment
Спасибо за замечание о сортировке без уведомления списка; похоже, это была моя проблема. Мне удалось обновить функцию navigatingTo и передать представление списка в модель данных, которая затем позволила мне вместо этого вызвать функцию, чтобы обновить ее. const recipeList = page.getViewById("recipeList"); page.bindingContext = mainPageModel; mainPageModel.recipeList = recipeList;, а затем вызовите this.recipeList.refresh(); в модели просмотра. - person Elocnatsirt; 21.10.2019