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:
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"
, thenstate.count + 10
will result in"110"
instead of the desired11
, 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:
Try It Now
Examine the code below, and it's output. How does it demonstrate the difference between Strings and Numbers?
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:
- 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:
- 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:
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
or32.5
- Array -
[ ]
or[ 1, "a", true ]
(can contain other data) - Object -
{ }
or{ "a": 123, "b": "XYZ" }
(can contain other data) - Boolean -
true
andfalse
(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
- 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
- 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 aStaticData
(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"}'
- 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.
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):
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):
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:
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
- Examine the code below. Do you see how the
for
template-tag "duplicates" the inner template for every item in the array of items?
- Try adding
|reversed
filter to theitems
, so it becomes{% for item in items|reversed %}
. What do you think this will do?
Try It Now
- Examine the code below. Do you see how the
for
template-tag "duplicates" the inner template for each station, in the Array of Objects?
- Examine this modification. This shows a more data, and a combination of an
if
and afor
. It allows it to add a "highlight" on ones that meet a certain criteria. Thegt 800
means "greater than 800".
- 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:
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:
Try It Now
Examine the JSON file below.
Consider the discussion questions below.
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)
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.
- Answer - To display data from a file like this, we can use the
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":
- Answer - Names on the left of
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
- Answer - The things on the right of the
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.
- Answer -
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:
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
http://127.0.0.1:6627/static/js/Modulo.js:833 ERROR: Uncaught TypeError: Cannot read properties of undefined (reading 'events')
Examine the code above.
Do you understand how the
get
filter accesses the data we need, and then thefor
template-tag loops through that data showing it in a grid format (thanks to CSSdisplay: grid
)?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
, andnull
- 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.