mirror of
https://github.com/noodlapp/noodl-docs.git
synced 2026-01-11 14:52:54 +01:00
Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: Michael Cartner <32543275+michaelcartner@users.noreply.github.com>
493 lines
20 KiB
HTML
493 lines
20 KiB
HTML
<!-- A step with just a popup -->
|
|
<div data-template="popup">
|
|
<video src="lesson-04_19_inspect.mp4"></video>
|
|
<h2>Data driven components</h2>
|
|
<p>Welcome back! In this fourth lesson we will learn how to use a data source to render a list of UI components. </p>
|
|
<p>In the last lesson we created a card component that we copied multiple times to create a list of cards. We will now learn how to generate the list of cards from data instead.</p>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- Ask user to look at the static data -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Static data</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_04-staticarray.mp4"></video>
|
|
<h2>Static data</h2>
|
|
<p>There are many ways that we can get datasets into our project. An easy way is to use the <strong>Static Array</strong> node.</p>
|
|
<p>This node acts as a text file and supports two standard data formats: JSON and CSV. The node in this lesson comes with a small dataset following the <strong>JSON format</strong>.
|
|
<p>The dataset holds all the data for the <i>Card Item</i>s we want to render. It contains a list of titles, categories and dates for each card.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
<!-- Ask user to look at the static data -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Data types</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<h2>Data types</h2>
|
|
<p>Noodl is built on top of JavaScript, a language with five primary data types: <strong>number</strong>, <strong>string</strong>, <strong>boolean</strong>, <strong>array</strong> and <strong>object</strong>.</p>
|
|
<p>The editor has nodes designed to store all the different data types, but the most common way of handling data in Noodl is by using objects in arrays.</p>
|
|
<p>Let's have a closer look at this pattern.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
<!-- Ask user to look at the static data -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Data in Noodl</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_04-staticarray.mp4"></video>
|
|
<h2>Objects in arrays</h2>
|
|
<p>There are multiple ways of storing data in Noodl, but for our usecase the <strong>Static Array</strong> node is perfect, since it's the simplest one.</p>
|
|
<p>If you look at the structure in the Static Array node you can see that it defines an <strong>array</strong> that contains multiple <strong>objects</strong>. Each object has a set of <strong>properties</strong>.</p>
|
|
<p>In Noodl, every object automatically gets a unique id attached to it. This means that we can look up a specific object (using its id) and get its data.</b>
|
|
<p>This is one of the more tricky concepts in Noodl, but let's go forward so we can experience how it works in practice.</b>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- Ask user to look at the static data -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Repeater node</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_08-repeater.mp4"></video>
|
|
<h2>Repeater node</h2>
|
|
<p>The <strong>Repeater</strong> node is used to generate visual components based on an array of objects. It takes a <strong>visual component</strong> as a template and renders it in place of the Repeater node in the Dom tree.</p>
|
|
<p>One component instance is generated and rendered for every object in the array.</p>
|
|
<p>Let's first remove the existing <i>Card Item</i> components from the DOM tree, add a Repeater node, and connect it up with our Static Array.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Lesson tasks</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<image src="../01_task.png"></image>
|
|
<h2>Time to get your hands dirty!</h2>
|
|
<p>During this lesson, you will be given multiple tasks. Spot them in the lesson timeline by the <i>Task</i> label.</p>
|
|
<p>If you get stuck you can get a hint by clicking the card in the timeline.</p>
|
|
<p>Some of the nodes graphs will already be set up for you beforehand. This is to keep the lessons short so that you can focus on learning one concept at a time. If it feels like magic at times, don't worry. It's just a concept you will learn in a later lesson.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"viewerpatheq":"/task-page"
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 280px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>Select the <strong><i>/task-page</i></strong> path in the <strong>Path Dropdown</strong></h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_02-selecttaskpage.mp4"></video>
|
|
<p>In this lesson you will be working on the page called <i>Task Page</i>. Navigate to it using the Path Dropdown in the Topbar.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"path":"/Task Page:%Page:%Group:#Content Container:0",
|
|
"exists":false
|
|
},
|
|
{
|
|
"path":"/Task Page:%Page:%Group:#Content Container:1",
|
|
"exists":false
|
|
},
|
|
{
|
|
"path":"/Task Page:%Page:%Group:#Content Container:2",
|
|
"exists":false
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 280px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>In the <strong>Task Page</strong> node graph, delete the three <strong>Card Item</strong> components</h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_07-delete components.mp4"></video>
|
|
<p>Select the <i>Card Item</i> components and <strong>press the backspace key</strong> to delete them.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"path":"/Task Page:%Page:%Group:#Content Container:%For Each",
|
|
"exists":true
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 280px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>Add a <strong>Repeater</strong> node as a child to the <strong>Content Container</strong> Group</h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_08-addrepeater.mp4"></video>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"path":"/Task Page:%Page:%Group:#Content Container:%For Each",
|
|
"paramseq": {
|
|
"template":"/Card Item"
|
|
}
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 320px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>On the <strong>Repeater</strong> node, set the <strong>template</strong> property to use the <strong><i>Card Item</i></strong></h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_09-cartitemtemplate.mp4"></video>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"from":"/Task Page:%Static Data",
|
|
"to":"/Task Page:%Page:%Group:#Content Container:%For Each",
|
|
"hasconnection":"items,items"
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 390px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>Connect the <strong>Static Array</strong> node to the <strong>Repeater</strong> node and send the <strong><i>items</i></strong> output to the <strong><i>items</i></strong> input</h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_09-connectarray.mp4"></video>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Mapping data</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_10_mappingdata.mp4"></video>
|
|
<h2>Mapping data</h2>
|
|
<p>You now have 4 cards in your UI, each with unique data. Let's walk through what happened here.</p>
|
|
<p>You already created the <i>Card Item</i> component in the last lesson. There you also created ports on the <i>Card Item</i> using a <strong>Component Inputs</strong> node. Those ports where hooked up to the properties we wanted to overwrite.</p>
|
|
<p>If the port names on the Component Inputs node matches the object keys in the Repeaters array, that data will automatically be passed to the rendered component.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item" style="width: 260px">
|
|
<header> </header>
|
|
<h2>Making clickable cards</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_13_connectclicked.mp4"></video>
|
|
<h2>Making clickable cards</h2>
|
|
<p>You have now built the basic system for showing cards (or any other type of list) from data. But to take this a step further you can also implement a way to make each card clickable and get its associated object so we can use that data somewhere else.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Component Outputs node</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_12_componentoutput.mp4"></video>
|
|
<h2>Component Outputs node</h2>
|
|
<p>Just as the Component Inputs node can be used to get data and signals into a component, you can use a <strong>Component Outputs</strong> node to send data and signals out from a component.</p>
|
|
<p>In this case we want to make the <i>Card Item</i> clickable, so that we can receive a signal from the card when it's clicked.</p>
|
|
<p>Let's start by creating a <strong>Component Outputs</strong> node in our <i>Card Item</i> component</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"path":"/Card Item:%Component Outputs",
|
|
"exists":true
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 340px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>In the <strong>Card Item</strong> node graph, create a <strong>Component Outputs</strong> node</h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_12_componentoutput.mp4"></video>
|
|
<p>Open the <i>Card Item</i>component, open the Node Picker and place a Component Outputs node anywhere in the node graph.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"path":"/Card Item:%Component Outputs",
|
|
"hasport": "Clicked"
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 270px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>Create a port called <strong><i>Clicked</i></strong></h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_13_clicked.mp4"></video>
|
|
<p>Remember that the port names are case sensitive</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"from": "/Card Item:%Group",
|
|
"to": "/Card Item:%Component Outputs",
|
|
"hasconnection": "onClick, Clicked"
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 450px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>Connect the <strong>Card</strong> Group node to the <strong>Component Outputs</strong> node and send the <strong><i>click</i></strong> output to the <strong><i>clicked</i></strong> input</h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_13_connectclicked.mp4"></video>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Repeaters and Component Outputs</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_14_outputs.mp4"></video>
|
|
<h2>Repeaters and Component Outputs</h2>
|
|
<p>If you just had a single Card component you would now be able to get the click event in the node graph where the <i>Card Item</i> component is placed.</p>
|
|
<p>Since the <i>Card Item</i>s are generated by the Repeater node, we can't access that port directly, so you need a way to know which of the four cards you click.</p>
|
|
<p>Earlier in this lesson we talked about how each object in the array has a unique id. This is really handy, as you can make the Repeater node give us the object id of the card instance we click.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Object node</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_15_objects.mp4"></video>
|
|
<h2>Object node</h2>
|
|
<p>The <strong>Object</strong> node gives you a way to access an object and its data anywhere in a project. You only need to provide it with an object id.</p>
|
|
<p>Objects are generally a good way to share data between different node graphs.</p>
|
|
<p>Let's look at how the Object and Repeater nodes can be used together to get the object data from a clicked <i>Card Item</i>.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"path":"/Task Page:%Model2",
|
|
"exists":true
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 350px">
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>In the <strong>Task Page</strong> node graph, place an <strong>Object</strong> node adjacent to the <strong>Repeater</strong> node</h3>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_15_objects.mp4"></video>
|
|
<p>Navigate to the <i>Task Page</i> component using the Component Panel in the Sidebar. Then open the Node Picker and create a new Object node.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"from": "/Task Page:%Page:%Group:#Content Container:%For Each",
|
|
"to": "/Task Page:%Model2",
|
|
"hasconnection": "itemActionItemId, modelId"
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 400px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>Connect the <strong>Repeater</strong> node to the <strong>Object</strong> node and send the <strong><i>item id</i></strong> output to the <strong><i>id</i></strong> input</h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_17_connectid.mp4"></video>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. It has tasks, so popup will only be shown when user clicks the item -->
|
|
<div
|
|
data-conditions='[
|
|
{
|
|
"from": "/Task Page:%Page:%Group:#Content Container:%For Each",
|
|
"to": "/Task Page:%Model2",
|
|
"hasconnection": "itemOutputSignal-Clicked, fetch"
|
|
}
|
|
]'
|
|
>
|
|
<div data-template="item" style="width: 400px">
|
|
|
|
<header>Task<span class="lesson-checkmark"></span></header>
|
|
<h3>Connect the <strong>Repeater</strong> node to the <strong>Object</strong> node and send the <strong><i>clicked</i></strong> output to the <strong><i>fetch</i></strong> input</h3>
|
|
</div>
|
|
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_18_clickfetch.mp4"></video>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header> </header>
|
|
<h2>Click the cards</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<video src="lesson-04_19_inspect.mp4"></video>
|
|
<h2>Click the cards</h2>
|
|
<p>Try <strong>hovering</strong> over the Object and pin the Data Popup so you can inspect the change when the <i>Card Item</i>.</p>
|
|
<p>As you can see you now get the object id, and all the associated data from the specific card that is clicked. This is a very powerful pattern that is used in almost every app.</p>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|
|
<!-- A step with an item in the bottom bar. No tasks, so popup will be shown automatically -->
|
|
<div>
|
|
<div data-template="item">
|
|
<header>Outro</header>
|
|
<h2>Congratulations!</h2>
|
|
</div>
|
|
<div data-template="popup">
|
|
<style>.lesson-item-popup {width: 600px !important;}</style>
|
|
<!--<img src="tutorial_card.png" style="cursor: pointer;" onclick="window.open('https://www.youtube.com/watch?v=TNnn0Gzj-H4&list=PL2eC2vS4uVoMbujQ5CiNtNuP7s7-UwNn-')"> -->
|
|
<h2>Congratulations!</h2>
|
|
<p>You've completed the fourth tutorial! Great job!</p>
|
|
<p>If you are new to programming, you might be interested in reading a little more about the different data types in JavaScript.</p>
|
|
<p>In the next tutorial we will learn how to use the click event on our cards to navigate to a detailed page with dynamic data from each card.</p>
|
|
<p>Happy Noodling!</p>
|
|
<!--<button style="width: 150px" onclick="window.open('https://www.youtube.com/watch?v=TNnn0Gzj-H4&list=PL2eC2vS4uVoMbujQ5CiNtNuP7s7-UwNn-')">WATCH TUTORIAL</button>-->
|
|
<button style="width: 150px" data-click="exitEditor">EXIT LESSON</button>
|
|
</div>
|
|
</div>
|
|
<!-- # -->
|
|
|
|
|