In Part 4 of this tutorial, we'll start exploring code that permits individual components to store, modify, and link together data, allowing for complex behaviors.

This is a challenging section! If you are new to JavaScript, try to understand as much as you can of this part of the tutorial, but don't feel bad if some parts seem extra hard.

We'll learn how to use StaticData, that lets us import JSON files or CSV file types, or APIs that use these types, into our Modulo components, so that we can use template tags to explore 3rd party data.

Before we get to these more powerful features of Modulo, we'll need to first explore Data Types, and how data props enable different JavaScript data types.

Data Types

Other Directives - All directives are "provided" by a CPart. That is, including CParts in your component definition may "enable" more directives in your HTML. Data-prop ([component.dataProp] or :=), for example, is a built-in feature of the Component, which means it's always available. Directives are not the main focus of this tutorial. To learn more, including how to author your own directives using JavaScript, see Directives. However, for the purpose of this tutorial we will have no need to use directives outside of the built-in directives that come with Modulo.

Before we go any deeper into data types, however, we need to explore "data props", and before that, we need to review directives. The term directives in Modulo refers to special attributes that you add to HTML to add extra functionality.. You can recognize a directive by spotting certain special characters in the attribute name. We've seen one in the previous tutorial section, [state.bind]. For example, <input [state.bind] /> is an input HTML tag with a [state.bind] directive. Some directives will have a square-bracket syntax (e.g. [ ]), while others might use other special characters to set them apart from "normal" attributes (e.g. := syntax we'll learn next). While re-rendering, Modulo scans the resulting DOM to set-up or "mount" any directives it encounters.

Directives are useful for a variety of tasks, ranging connecting CParts to each other, to more complicated modifications to DOM elements.

The dataProp directive

We'll learn one more directive next: data prop or := syntax

Typically, when we add attributes to anything, whether it is a CPart or even just in regular HTML, the attribute value can only be a string. This means when we did <State count="1" ... > previously, we made a mistake: The count variable didn't get assigned to 1 the Number, but rather "1" the String. To fix it, we do the following:

<State count:=1 color="blue" ></State>

Data type? If you are new to coding, you might be confused by this term. It's a little like a file format for variables: Instead of JPG, DOCX, and ZIP, we have Numbers, Strings, Arrays, Objects, Booleans, etc. This collection of types is what makes up the "JSON" format, which Modulo uses.

This is called a data prop directive. You can identify a data prop directive (:=), by spotting an attribute name that is suffixed with a colon right before the equal sign, like this: attributeName:=value.

The types of data

Modulo uses the same data types as JavaScript and the JSON file format, which Modulo uses extensively. The remainder of this section will highlight the most useful types for new Modulo developers:

Why don't we use "strings" for numbers? Using strings of digits (i.e. in quotes) instead of the numbers themselves means that things like arithmetic won't work as intended. Example: If state variable count="1", then state.count + 10 will result in "110" instead of the desired 11, since it's a string of digits, so "1" + "10" = "110"

Strings

String is the default. If you use = like a regular HTML attribute, it will be a "plain old" String. The word "String" refers to a "string of characters", and is used for text, whether it's a single letter, a word, a paragraph, or an entire book.

Numbers

If you use the := syntax followed by a number, like :=10 or :=32.4, you create a value of the Number type. This is useful for numeric data that you want to do calculations on. That is to say, Numbers can actually "do math", as opposed to strings that you'd only combine end-to-end, but not "do math". For example, 5 + 5 = 10 for Numbers, while "5" + "5" = "55" for Strings.

Examples of both Strings and Numbers are below:

<State message="Hello world!" longer=" Strings can be more than one line. " count:=1 debt:=-2 x:=912.3 y:=123.234 ></State>
Try It Now

Examine the code below, and it's output. How does it demonstrate the difference between Strings and Numbers?

<Template> Adding strings: {{ state.a|add:state.b }}<br /> Adding numbers: {{ state.c|add:state.d }}<br /> </Template> <State a="10" b="20" c:=10 d:=20 ></State>

Boolean and null

In addition to Strings and Numbers, there are 3 special "placeholder" or "on-off switch" values that can be used:

  • true, false (called Booleans)
  • null

These have their uses, such as using true and false to store the value of checkboxes, or using null as a placeholder value.

Container types

Continuing on our tour of data types, let's examine "container types" (ones that contain other data). In our case, container types are also "iterable types" (ones you can "loop on", e.g. with a for loop, as we'll learn later).

Arrays

Iterables - There are some types of data that are called "iterable". That means you can "iterate" over them, or repeat code for them. A good rule of thumb is if the data in question is "plural". Plural data is iterable. For example, if you want to show a single profile picture, that's not plural. If you want to show every profile picture (whether that is 0 or 100), that matches a search result, that is "plural", and that is when we want to use an iterable.

Warning: This stuff gets trickier! Arrays are more complex data types, so it might take more practice to get the hang of them!

Arrays are the most important type of "container type" or "iterable type" in JavaScript. This means, a type that can contain other types. This means you can say it's an "Array of Numbers" (to refer to a certain collection of numbers, e.g. data you want to chart or graph), or an "Array of Strings" (to refer to a collection of items of text, e.g. the usernames of people who are present in a chat room).

Eventually, we'll learn how to take this data and then display it, or manipulate it, in order to build applications, but for now let's start with the syntax. In this case, let's examine an Array of Numbers and two Array of Strings, called dataset, cities, and 'students' respectively:

<State dataset:='[ 103, 32, 15, 100 ]' cities:='[ "Berkeley", "Porto Alegre" ]' students:='[ "Alice", "Bob", "Candace" ]' ></State>
  • Array syntax summary: '[ (opening), ]' (closing), and contents seperated with comma: ,

Objects

Objects are like arrays in that they contain other data, but instead of having an ordered sequence of items, they have them behind "keys", which are strings designations or labels for values, which can be any other type. Objects are sometimes called "dictionaries" in other programming languages, because they are a lot like a dictionary, consisitng of a words of phrases (keys), followed by their "definitions" (values).

The format for objects is like: { "key": "value", "key2": "another value" }

See below for a more complete example:

<State info:='{ "title": "Roller coaster", "ticketPrice": 123.5 }' ></State>
  • Object syntax summary: '{ (opening), }' (closing), : (seperates the key from the value) and , (seperates each entry)

Arrays of Objects

When we access real-world data, whether those are blog articles in a publishing site, or a data items in a dashboard, they often "arrive formatted" as what's called a JSON array of objects.

This is a much more complicated data format that builds on the previous two data formats. We'll encounter it again in a moment, when we start using StaticData. Look over the following format containing some imaginary "traffic rating" about two train stations. Don't worry about understanding every aspect about the format, but focus instead on the big picture of what this data might be trying to express:

<State stations:='[ { "name": "Embarcadero Station - San Francisco", "trafficRating": 1353 }, { "name": "19th Street Station - Oakland", "trafficRating": 732 } ]' ></State>

Summary: JSON type list

To summarize this, look at this list of JSON types, and see if you can understand the examples given of each type of data:

  • String - "Hello!", "how are you", "f$J^&m$j", or the empty ""
  • Number - 42 or 32.5
  • Array - [ ] or [ 1, "a", true ] (can contain other data)
  • Object - { } or { "a": 123, "b": "XYZ" } (can contain other data)
  • Boolean - true and false (no other possible values)
  • Other: null

Final notes on Data Props

  • Keep in mind that data props directives are not the same as the Props CPart. They are, however, related, in that the Props CPart looks for both regular attributes and data props: You can in fact set any Props attributes with the := syntax, for data other than Strings.
  • There are a few more types as well: null, true, false, which are simple types used to "flag" items, or set a property "on and off", or for placeholder values
  • Data props support any JSON literal type. Technically, data props values can have double quotes just like normal String-based attributes. However, as a stylistic convention, you may omit the double quotes for any one-word value, and should use only single quotes for complex types, such as JSON-formatted Arrays or Objects. See below for stylistic examples of data props with different types:
Try It Now
  1. Let's see how we can use filters to "poke" at an Array. Examine the next bit of code. Do you see how you can access individual items in an Array using the |get filter? Do you see how |json is used to show State in JSON syntax, and five
<Template> <p>Item at index 3: <tt>{{ state.items|get:3 }}</tt> </p> <p>Items separated by a dash: {{ state.items|join:"-" }} </p> <hr /> <input [state.bind] name="str1" /> <input [state.bind] name="str2" /> <input [state.bind] name="num" type="number" /> <p> State in JSON format: <pre>{{ state|json:2 }}</pre> </p> </Template> <State str1="hello" str2="123" items:='[ "toothbrush", "umbrella", "my bag", "laptop", "charger" ]' num:=10 ></State>
  1. Extra: Try using the following snippet in the different demos in this tutorial for "peaking" at state in JSON format: <pre>{{ state|json:2 }}</pre>
Comprehension Questions
  • What do you think the |json filter is for?
    • Answer 1: It displays the given data into JSON format. It's useful to quickly checking the exact content of a state variable, or data from any other source.
    • Answer 2: The output of this filter can be pasted into attributes with the syntax of data:='{ ... }', or into the content of a StaticData (covered later). This is useful for "saving" useful state configurations during testing.
  • Why do you think |get:3 produces "laptop"?
    • Answer: Modulo starts counting the "index" of Arrays at "index number 0". This is the same behavior as JavaScript.
  • What is the purpose of JSON format?
    • JSON is a standard file format that Modulo can read in. Any (strictly) JSON formatted data structure can be inserted in a Modulo dataProp, e.g. dataprop:='{"Hello": "World"}'

The "for" loop template tag

As was introduced in the previous section, in addition to filters, the Modulo templating language also support powerful "template tags", which allow for more complicated custom behavior. We looked at the {% if %} template tag previously. Now we'll practice the {% for %} template tag.

For loops: Applications

Common example uses of for loops:

  • Each blog post needs it's own <li> element
  • Each link in an Array gets it's own <a> element in a nav bar
  • Each student from a CSV file needs their grade listed in a table
  • Each country in a world map from a JSON file gets a different tint based on per-capita CO2 emissions
  • Each product from a backend-API powered database has a tile in a e-commerce web store app, each with a different "buy now" link

Note how every one of these examples start with the word "Each". Many programming languages and frameworks -- Modulo included -- concept call this concept a "for each loop", or simply a "for loop". In Modulo, a "for loop" is a type of template tag, that allows us to repeat a template for each item in a "plural" (collection) type of data. This lets us build websites that do all of the above things.

The for-tag

The "for-tag" is for when we want to duplicate a bit of template over and over for a repetitive bit of data. For example, if we want to template "for every article", or "for every pin in a world map", or "for every post in an article comment section". Each of these "for" statements refers to some plural thing that we want to have a similar style duplicated across, using the same HTML template for each item in that collection.

For example, imagine showing a paragraph for every student in a class's roster (assuming data like in the students:= State data example above):

{% for name in state.students %} <p>Name on roster: {{ name }}</p> {% endfor %}

A for loop can also loop through other types of data, such as the very popular Array of Objects, formatting it in a reasonable way (assuming data like in the stations:= State data example above):

{% for station in state.stations %} <p>{{ station.name }} | TRAFFIC SCORE: {{ station.trafficRating }}</p> {% endfor %}

In this example, the {{ station.name }} and {{ station.trafficRating }} refer to templating the individual values within the station object in the array of stations.

Like the "if", for has an "endfor", which it uses to designate the portion of the temlpate it will repeat. Unlike "if", it can use the template it 0 times, 1 time, or 2+ times (if-tags can use the template only 0 times or 1 time, but can never "duplicate" the template and use it 2+ times).

Template tag gotchas

Important syntax note: Always put templating tags inside of attribute values. For example:

<div class="{% if state.show %}visible{% endif %}"> ...hidden things... </div>

Do you see how the class="..." goes around the if? This is the correct way to do it. It is incorrect to make the entire attribute optional. That is to say, syntax like {% if state.show %}class="visible"{% endif %} is incorrect. Otherwise, you might see mysterious ="" to appear in your code due to the browser misinterpreting the syntax.

Try It Now
  1. Examine the code below. Do you see how the for template-tag "duplicates" the inner template for every item in the array of items?
<Template> <ol> {% for item in state.items %} <li>{{ item }}</li> {% endfor %} </ol> </Template> <State items:='[ "toothbrush", "umbrella", "my bag", "laptop", "charger" ]' ></State>
  1. Try adding |reversed filter to the items, so it becomes {% for item in items|reversed %}. What do you think this will do?
Try It Now
  1. Examine the code below. Do you see how the for template-tag "duplicates" the inner template for each station, in the Array of Objects?
<Template> {% for station in state.stations %} <div>{{ station.name }}</div> <div>{{ station.trafficRating }}</div> {% endfor %} </Template> <State stations:='[ { "name": "Embarcadero", "trafficRating": 1353 }, { "name": "19th St", "trafficRating": 732 } ]' ></State> <Style> :host { display: grid; grid-template-columns: 1fr 1fr; } </Style>
  1. Examine this modification. This shows a more data, and a combination of an if and a for. It allows it to add a "highlight" on ones that meet a certain criteria. The gt 800 means "greater than 800".
<Template> <h3>Name</h3> <h3>City</h3> <h3>Use</h3> {% for station in state.stations %} <div>{{ station.name }}</div> <div>[{{ station.city }}]</div> <div class="{% if station.trafficRating gt 800 %}warning-alt{% endif %}">{{ station.trafficRating }}</div> {% endfor %} </Template> <State stations:='[ { "name": "Embarcadero", "city": "SF", "trafficRating": 1253 }, { "name": "West Oakland", "city": "OAK", "trafficRating": 695 }, { "name": "12th St", "city": "OAK", "trafficRating": 853 }, { "name": "19th St", "city": "OAK", "trafficRating": 732 } ]' ></State> <Style> :host { display: grid; grid-template-columns: 1fr 1fr 1fr; } .warning-alt { border: #ffeeee 2px solid; background: #ffaaaa; } </Style>
  1. Local file challenge: This one is tricky, but think about if there's a way you can reduce your code size and reuse by "refactoring" repetitive code in your local project into a State data and a for-loop.

StaticData

StaticData is a CPart used to import data from a JSON file format or CSV file format source, such as a file or API. Unlike State, it is for "static" or unchanging data. When building or deploying, it will be bundled together for speedy look-ups.

Intro to the JSON file format

JSON files are a format for storing data. There are many editors and tools for using them -- your editor may already be able to!

What are JSON files like? The best way to learn is by looking at one: https://www.gov.uk/bank-holidays.json

If you click on that link, you'll see something like:

{"england-and-wales":{"division":"england-and-wales","events":[{"title":"New Year’s Day","date":"2018-01-01","notes":"","bunting":true},{"title":"Good Friday","date":"2018-03-30","notes":"","bunting":false},{"title":"Easter Monday", ...

This is hard to read. But if you look closely through it, you recognize that it contains information about holidays in the UK, starting in the year 2018, as provided by the government of the UK. If used correctly, this data could be useful for quickly assembling a scheduling app, for example.

In Modulo, we can use the StaticData CPart to access this file:

<StaticData -src="https://www.gov.uk/bank-holidays.json" ></StaticData>
Try It Now
  1. Examine the JSON file below.

  2. Consider the discussion questions below.

  3. Challenge: Modify the code to correctly access data in the JSON file and display the first event title for England and Wales (e.g. "New Years Day") (Solution below)

<Template> <pre>{{ staticdata|json:2 }}</pre> </Template> <StaticData -src="https://www.gov.uk/bank-holidays.json" ></StaticData> <Style> pre { height: 250px; overflow: auto; } </Style>
Comprehension Questions
  • How is it displaying the entire file, formatted like that?

    • Answer - To display data from a file like this, we can use the |json filter in a HTML pre-formatting <pre></pre> tag. Using the |json:2 argument gives us 2 spaces for indentation.
  • How do you identify keys of this file?

    • Answer - Names on the left of : are called "keys" and/or "properties". They are labels for specific parts of the data set.
    • Examples - "england-and-wales":, "title":, "division":, or "events":
  • How do you spot the values of this file?

    • Answer - The things on the right of the : are called the "values". These are typically the data you actually want. You can use the labels to the access the values.
    • Examples - : "New Years Day", : "2018-01-01", or : true
  • How would you access the title of the first event?

    • Answer - |get:"england-and-wales.events.0.title"
    • Explanation - Why england-and-wales? Because it's the first key behind the :. Why .events? Because it's the next key that lets us access the big Array (hint, the [ and ]) of the "main data". Why .0? Because programming languages start counting at 0, so the first thing is accessed at index 0. Finally, the .title accesses the specific value that we want.

Drilling down with |get

So, to access the data we want, to "drill down" so-to-speak, we can use the |get filter. This lets us string together with dots (.) as many "keys" as we'd like to access what we want. For example, to access the first holiday, |get:"england-and-wales.events.0.title". Example:

<Template> <p><strong>First event of the year in England:</strong> {{ staticdata|get:"england-and-wales.events.0.title" }}</p> </Template> <StaticData -src="https://www.gov.uk/bank-holidays.json" ></StaticData> <Style> pre { height: 250px; overflow: auto; } </Style>

Okay, that's good for accessing exactly 1 value. However, the more useful thing would be to go just to the level of the Array (e.g. "events": [) and then use a {% for %} loop to go through it all.

See how applying these techniques can create a table with a {% for %} template tag in this next TRY IT NOW.

Try It Now
<Template> <h3>Title</h3><h3>Date</h3> {% for event in staticdata|get:"england-and-wales.events" %} <div>{{ event.title }}</div> <div>{{ event.date }}</div> {% endfor %} </Template> <StaticData -src="https://www.gov.uk/bank-holidays.json" ></StaticData> <Style> :host { height: 200px; overflow: auto; display: grid; grid-template-columns: 1fr 1fr; } div { font-size: 0.8rem; } </Style>
http://127.0.0.1:6627/static/js/Modulo.js:833
ERROR: Uncaught TypeError: Cannot read properties of undefined (reading 'events')
  1. Examine the code above.

  2. Do you understand how the get filter accesses the data we need, and then the for template-tag loops through that data showing it in a grid format (thanks to CSS display: grid)?

  3. Local file challenge: Try accessing other data sets you find. Can you display a table or details of some data set or JSON-based API you find online? For example, if you are fan of the Pokemon franchise, you might enjoy using the PokeAPI. Or, try using GitHub's API. Many more are available here: https://github.com/public-apis/public-apis


Part 4: Summary

Key terms

  • Directive - A special type of HTML attribute that "hooks in" functionality to otherwise plain HTML elements. Three built-in directives include:
    • := - "data-prop" assignment, allowing for assigning to JavaScript values such as functions and/or primitive JavaScript data types in JSON syntax
    • @click - attach event listener to element
  • Data types - the collection of different types of data that JavaScript, and thus Modulo, can read. They consist of: String, Number, Boolean, Array, Object, and null
  • Template tag - A more advanced type of Template code that lets us repeat or optionally include other template code based on data contained in state, props, or from a static data CPart
    • for-statement - template tags for duplicating portiosn of template code for every item in an Array
  • JSON - A file format for storing data that Modulo can read
  • StaticData - The CPart for reading in JSON or CSV files

Next step

You're almost done with the tutorial! The last section goes deeper into attaching events, before finally dipping into use of the Script CPart, which enables you to add JavaScript code into your components.

Part 5: Events and Scripts »