Turning your attention to the next screen, we want to display a list of cards of the major arcana cards. We will show the emoji and name of the card in a list, then when you tap the list item, a modal window will appear. In this lesson, you'll work with a plugin and a ListView.

Page prep work

First, add styles to this page. The styles won't be used elsewhere, so you can call them scoped styles, Replace the <style> block in CardList.vue with this:

<style scoped>
    .meaning-card {
        margin: 10;
        padding: 5;
    }

    .arrow {
        margin-right: 5;
    }

    .arrow2 {
        margin-right: 5;
    }
</style>

Prep the page to receive data by importing the cards.js data again and building placeholders in the data() object by overwriting the <script> block:

<script>
import {Cards} from "../data/cards";
const Detail = {};
export default {
    data() {
        return {
            cards: Cards,
            name: "",
            meaning_up: "",
            meaning_rev: "",
            emoji: "",
            value: "",
            allCards: [],
            detailPage: Detail
        };
    },
}
</script>

Here, you created an array of allCards, as well as a detailPage that currently contains a blank object.

Finally, edit the markup in <template>, overwriting everything in between the template tags to show a page title:

<GridLayout rows="auto,*" verticalAlignment="top">
	<Label row="0" text="Card Meanings" class="title med" />
</GridLayout>

Get and display all cards

Next, add a method called getAllCards() and call it in the created() lifecycle hook.

Add a method property under the last comma in the data method to loop over the card data:

methods: {
    getAllCards() {
        this.cards.forEach((card, index) => {
            if (card.type == "major") {
                this.allCards.push({
                    name: card.name,
                    emoji: card.emoji,
                    value: card.value,
                    meaning_up: card.meaning_up,
                    meaning_rev: card.meaning_rev
                });
            }
        });
    }
},
created() {
    this.getAllCards();
}

Then, add a ListView to the markup. Under the card meaning label, add a StackLayout with a ListView:

<StackLayout row="1" class="meaning-card" orientation="vertical">
	<ListView class="list-group" for="item in allCards" backgroundColor="transparent" separatorColor="transparent">
		<v-template>
			<GridLayout columns="50,*" rows="*" class="list-item list-item-name">
				<Image col="0" :src="'~/assets/emoji/' +item.value+ '.png' " class=" emoji" />
				<Label col="1" :text="item.name" class="lab" verticalAlignment="center" />
			</GridLayout>
		</v-template>
	</ListView>
</StackLayout>

What's a v-template? It's special to NativeScript-Vue, and is basically syntactic sugar for scoped slots

Now you can see, on the second screen, a scrollable list of cards with their emoji and name. Nice!

Enhance the screen with a popup

We want the cards on this screen to include a modal popup with the full meaning, both up and reversed, of the card. There's a nice NativeScript plugin we can use called Windowed-Modal that creates a nice modal, so let's use that.

If you need enhanced functionality in your NativeScript app, check out the marketplace.

First, install this plugin by clicking the + in the Playground Explorer and selecting 'Add NPM package'. Type nativescript-windowed-modal in the search pane and install the most recent version of the plugin. You'll find a folder installed in the root of your app.

Normally when installing a plugin in your app, the files will go into your node_modules folder. This is a playground app, so the architecture is a little different.

Next, invoke the plugin by going to app.js in your app root by importing, then registering, the plugin. Add these lines above new Vue:

import { ModalStack, overrideModalViewMethod, VueWindowedModal } from './nativescript-windowed-modal';
overrideModalViewMethod();

Vue.registerElement('ModalStack', () => ModalStack);
Vue.use(VueWindowedModal);

Whenever you need to use a plugin that adds elements to your template markup, you register it in app.js or main.js in this way

Now, build out the modal window in the Detail constant that you created earlier.

Overwrite const Detail = {}; in CardList.vue with this markup:

const Detail = {
	props: ['name', 'value', 'meaning_up', 'meaning_rev'],
	template: `
        <ModalStack class="modal-container">
            <GridLayout class="card modal" rows="auto,auto" verticalAlignment="middle">
                <Button row="0" @tap="$modal.close" class="fa close" 
                    text.decode="&#xf0c9;" horizontalAlignment="right" />
                <StackLayout row="1" ref="meaningContainer" class="list-item 
                    list-item-meaning">
					<Image col="0" :src="'~/assets/emoji/' + value + '.png' " class=" emoji_window" />
                    <Label col="1" :text="name" class="card-title" 
                        style="text-align: center;padding-bottom: 24;" />
					    <GridLayout columns="20,*" rows="*,*">
                            <Image col="0" row="0" class="arrow" verticalAlignment="top" 
                                src="~/assets/arrow_up.png" style="margin-top: 5; margin-right: 10" />
                            <Label col="1" row="0" verticalAlignment="top" :text="meaning_up" 
                                textWrap="true" style="margin-bottom:25; font-size: 16;" />
                            <Image col="0" row="1" class="arrow2" verticalAlignment="top" 
                                src="~/assets/arrow_down.png" style="margin-top: 5; margin-right: 10" />
                            <Label col="1" row="1" verticalAlignment="top" :text="meaning_rev" textWrap="true" 
                                style="font-size: 16" />
					    </GridLayout>
				</StackLayout>
        </GridLayout>
    </ModalStack>
`,
};

Take a look at this markup. It looks familiar by now because it's just displaying a popup card of Tarot meanings. Notice that we must pass props into the Detail const for each card we want to show.

To see this modal in action, there are some more things to do.

Add a comma at the close of the getAllCards method, and add a method to handle the opening of the modal:

showDetailPageModally(item) {
    this.$showModal(Detail, {
        props: {
            name: item.name,
            value: item.value,
            meaning_up: item.meaning_up,
            meaning_rev: item.meaning_rev
        }
    });
},

Then, add a click handler on the GridLayout that is the building block of the list. After the <v-template> tag, edit the GridLayout:

<GridLayout @tap="showDetailPageModally(item)" columns="50,*" rows="*" class="list-item list-item-name">

Go ahead and tap around! You should see the meanings of the cards.

😍 Bravo! You've made a lot of progress! Next, we just have to build one more screen!