nativescript-vue icon indicating copy to clipboard operation
nativescript-vue copied to clipboard

Expose `itemTemplateSelector ` for the `ListView` ns-core Layout

Open adel12790 opened this issue 2 years ago • 6 comments

What problem does this feature solve?

It will have better performance when it comes to loading huge lists, as the item selector will fetch and feed the views that only map the selector criteria.

What does the proposed API look like?

<ListView :items="<collection-containing-objects>" :itemTemplateSelector="selector">
    <v-template name="banner">
    ....
    </v-template>
    <v-template name="content">
    ...
    </v-template>
</ListView>

selector(item) {
    return <expression-based-on-item-content> ? 'banner' : 'content';
}

adel12790 avatar Mar 29 '22 18:03 adel12790

This should already work iirc

rigor789 avatar Mar 29 '22 19:03 rigor789

I have created this small demo clean app to try out on it. https://github.com/adel12790/ns-vue-list-demo

Outputs an error and crashes on both iOS and Android. TypeError: Cannot read property 'scopedFn' of undefined

I have tried to search for this error, but I couldn't find a reasonable answer.

I have checked the @ns/core module packages @nativescript/core/ui/list-view and I guess we need to specify an itemTemplates wrapper to be able to use the selector.

But I couldn't manage to do it.

adel12790 avatar Mar 30 '22 07:03 adel12790

Same here I'm using NativeScript 7.3.0 but I can't seem to get it to work. Documentation seems lacking with regards to this subject. I've based my code on examples using vanilla NativeScript and NativeScript Angular but my code resulted in:

TypeError: Cannot read property 'scopedFn' of undefined

I've been trying to find an example of how it should be used with NativeScript Vue but no luck so far.

dangrima90 avatar Apr 05 '22 16:04 dangrima90

I've investigated a bit and to me there seems to be a bug in the mounted lifecycle hook:

https://github.com/nativescript-vue/nativescript-vue/blob/8341c128860e7874b990269ffd063f802ecc9ae8/platform/nativescript/runtime/components/v-template.js#L17-L29

If I'm understanding the code correctly here in line 27 it's always the default slot that's being passed. The error TypeError: Cannot read property 'scopedFn' of undefined only occurs when there isn't a template with the name default, just like @adel12790's example.

This will break

<template>
    <GridLayout class="list-wrapper">
        <ListView class="list"
            :items="dataList"
            :itemTemplateSelector="selector"
        >
            <v-template name="fruit">
                <Label :text="`Sweat ${item.name}`" />
            </v-template>
            <v-template name="veggies">
                <Label :text="item.name" />
            </v-template>
        </ListView>
    </GridLayout>
</template>

This won't break, but only default template will be used

<template>
    <GridLayout class="list-wrapper">
        <ListView class="list"
            :items="dataList"
            :itemTemplateSelector="selector"
        >
            <!-- Set template to "default" or else don't set a name,
                 which internally will set template name to "default" -->
            <v-template name="default">
                <Label :text="`Sweat ${item.name}`" />
            </v-template>
            <v-template name="veggies">
                <Label :text="item.name" />
            </v-template>
        </ListView>
    </GridLayout>
</template>

dangrima90 avatar Apr 05 '22 17:04 dangrima90

So what if we want to have templates branching within the list, so we might add the default for fallbacks, but still need the other ones to show based on the item selector.

adel12790 avatar Apr 08 '22 13:04 adel12790

@adel12790 I've managed to find out how to make it work. It's listed in the documentation and I think last time I missed it.

So you have to use the if prop - Reference.

Using the same example as above you can have something like so:

<template>
    <GridLayout class="list-wrapper">
        <ListView class="list" for="item in dataList">
            <v-template if="item.type === 'fruit'">
                <Label :text="`Sweat ${item.name}`" />
            </v-template>
            <v-template if="item.type === 'veggies'">
                <Label :text="item.name" />
            </v-template>
        </ListView>
    </GridLayout>
</template>

According to the documentation in the if prop you can use the following variables:

image

dangrima90 avatar Jun 28 '22 06:06 dangrima90