“For Each”

Outlines are closely related to JavaScript arrays, and they often have a one-to-one correspondence. For example, a simple shopping list outline is nothing more than an array of items expressed vertically in sequence. And so it stands to reason that JavaScript functions designed to iterate arrays would be useful in constructing OmniOutliner outline documents.

The forEach() method calls a provided function once for each element in an array, in order. This method is perfectly designed for constructing outlines. Note: forEach() does not execute the function for array elements without values.

For example, in the following script, the forEach() method is applied to the array of children of the rootItem. Note that the method’s processing function is passed each of the children, one-at-a-time, represented by the pass-through variable titled: “child”

rootItem.children.forEach(function(child){//function code})

The function code can then be applied to the passed “child” object.

Let’s use the forEach() method to clear the current contents of our outline document.

DO THIS ►

Copy and paste the following script into the console window, and execute it by pressing the Return key.

rootItem.children.forEach(function(child){child.remove()})
omnioutliner:///omnijs-run?script=rootItem%2Echildren%2EforEach%28function%28child%29%7Bchild%2Eremove%28%29%7D%29

The script will iterate the list of the top-level outline items and delete each instance by applying the remove() method to it. The result will be a blank outline document.

blank-doc

Array to Outline

Now that the document has been cleared, let’s use the forEach() method to construct a simple single-level outline by iterating an array of planet names and creating a new outline entry for each one.

In the following example, note how the content of the created items is set by appending the topic property to the method, and then assigning it a value. This single-line technique (line 3) is perfect for those situations where you don’t need to store a reference to the newly created item.

DO THIS ►

Copy and paste the following script into the console window, and execute it by pressing the Return key.

planets = ['Mercury','Venus','Earth','Mars','Jupiter','Saturn','Uranus','Neptune','Pluto'] planets.forEach(function(planet){ rootItem.addChild().topic = planet })
omnioutliner:///omnijs-run?script=planets%20%3D%20%5B%27Mercury%27%2C%27Venus%27%2C%27Earth%27%2C%27Mars%27%2C%27Jupiter%27%2C%27Saturn%27%2C%27Uranus%27%2C%27Neptune%27%2C%27Pluto%27%5D%0Aplanets%2EforEach%28function%28planet%29%7B%0A%09rootItem%2EaddChild%28%29%2Etopic%20%3D%20planet%0A%7D%29
Make Planet Items

The result of the script will be a simple outline of top-level items:

simple-outline

As you can see, it’s easy to create a simple outline from a single array of data. Next, we’ll use the forEach() method to create a more complex outline, one with multiple levels of entries.

Before creating the new outline, clear the existing entries.

DO THIS ►

Copy and paste the following script into the console window, and execute it by pressing the Return key.

The outline is now cleared. For the next example, we’ll use data from two arrays to create a multi-level outline.

The “item index” Parameter

The forEach() method takes a processing function as its sole parameter. By default, the function must include a pass-through variable that will contain a reference to the array item being processed. However, there are two other optional parameters for the function that can be represented with variables:

Using the optional item index pass-through, we can combine data from two aligned arrays to create an outline. Arrays are said to be “aligned” when they are of the same length and their data is related and in the same order. The following example uses two arrays, a list of the planets, and a list of their moons. Both arrays are of the same length, with related content in the same order.

planets = ['Mercury','Venus','Earth','Mars','Jupiter','Saturn','Uranus','Neptune','Pluto'] moons = [[],[],["Moon"],["Deimos", "Phobos"],["Ganymede","Callisto","Io","Europa"],["Titan","Rhea","Iapetus","Dione","Tethys","Enceladus"],["Titania","Oberon","Umbriel","Ariel","Miranda"],["Triton","Proteus"],["Charon","Hydra","Nix"]] planets.forEach(function(planet,index){ item = rootItem.addChild(null,function(child){ child.topic = planet }) moons[index].forEach(function(moon){ item.addChild().topic = moon }) })
omnioutliner:///omnijs-run?script=planets%20%3D%20%5B%27Mercury%27%2C%27Venus%27%2C%27Earth%27%2C%27Mars%27%2C%27Jupiter%27%2C%27Saturn%27%2C%27Uranus%27%2C%27Neptune%27%2C%27Pluto%27%5D%0Amoons%20%3D%20%5B%5B%5D%2C%5B%5D%2C%5B%22Moon%22%5D%2C%5B%22Deimos%22%2C%20%22Phobos%22%5D%2C%5B%22Ganymede%22%2C%22Callisto%22%2C%22Io%22%2C%22Europa%22%5D%2C%5B%22Titan%22%2C%22Rhea%22%2C%22Iapetus%22%2C%22Dione%22%2C%22Tethys%22%2C%22Enceladus%22%5D%2C%5B%22Titania%22%2C%22Oberon%22%2C%22Umbriel%22%2C%22Ariel%22%2C%22Miranda%22%5D%2C%5B%22Triton%22%2C%22Proteus%22%5D%2C%5B%22Charon%22%2C%22Hydra%22%2C%22Nix%22%5D%5D%0A%0Aplanets%2EforEach%28function%28planet%2Cindex%29%7B%0A%09item%20%3D%20rootItem%2EaddChild%28null%2Cfunction%28child%29%7B%0A%09%09child%2Etopic%20%3D%20planet%0A%09%7D%29%0A%09moons%5Bindex%5D%2EforEach%28function%28moon%29%7B%0A%09%09item%2EaddChild%28%29%2Etopic%20%3D%20moon%0A%09%7D%29%0A%7D%29

 1  Source Array • The main array is a list of the planets (yes, I include Pluto in that list!)

 2  Aligned Array • A second array comprised of the names of the larger moons of each planet (Did you know that Jupiter has over 60 moons?). This list is in the same order as the source list.

 4-11  forEach() method • Iterating the items of the source array using a processing function that has the required array item variable, as well as the option array item index pass-through variable.

 5-7  addItem() method • A new child of the rootItem is created and its value set using the passed-through item (planet) of the source array containing the names of the planets.

 8-10  forEach() method • A second forEach() method is used to create children for the previously created child. Notice that the passed-through array item index (index) is used to get the names of the corresponding moons from the secondary moons array. Also note that the planet child (moon) is created and its value set using a single-line of code  9  by appending the topic property to creation method and then setting its value. (Very clever!)

DO THIS ►

Copy and paste the previous script into the console window, and execute it by pressing the Return key.

Double Arrays

The result of the script will be the multi-level outline shown below. (I’ve expanded two of the top-level items to reveal their children.)

planets-and-moons--01

Object Data to Outline

In the previous example a multi-level outline was created using two data sources (arrays). In the following example, we’ll examine how to create a multi-level outline from a single data source that is a complex JavaScript object.

First, clear the outline of its existing content.

DO THIS ►

Copy and paste the following script into the console window, and execute it by pressing the Return key.

Using JSON (JavaScript Object Notation), data can be stored in either arrays or objects. A JavaScript object is a record of information, represented using an identifying key with a corresponding a data value.

JavaScript objects are placed within curly brackets, with their key and value delimited by a colon ({key:value}). You’ll find that key/value pairing is often used when dealing with stored data.

The following script example demonstrates how to extract the data from a complex JavaScript object and use it to create a multi-level outline in OmniOutliner. In this example, each key is unique — not matching any other key in the parent object. However, it is also common to use the same key for multiple objects, as we’ll examine in another example later in this section.

planetData = {"Mercury":[],"Venus":[],"Earth":["Moon"],"Mars":["Deimos", "Phobos"],"Jupiter":["Ganymede","Callisto","Io","Europa"],"Saturn":["Titan","Rhea","Iapetus","Dione","Tethys","Enceladus"],"Uranus":["Titania","Oberon","Umbriel","Ariel","Miranda"],"Neptune":["Triton","Proteus"],"Pluto":["Charon","Hydra","Nix"]} planets = Object.keys(planetData) planets.forEach(function(planet){ row = rootItem.addChild( null, function(child){child.topic = planet} ) moons = planetData[planet] moons.forEach(function(moon){ row.addChild().topic = moon }) })
omnioutliner:///omnijs-run?script=planetData%20%3D%20%7B%22Mercury%22%3A%5B%5D%2C%22Venus%22%3A%5B%5D%2C%22Earth%22%3A%5B%22Moon%22%5D%2C%22Mars%22%3A%5B%22Deimos%22%2C%20%22Phobos%22%5D%2C%22Jupiter%22%3A%5B%22Ganymede%22%2C%22Callisto%22%2C%22Io%22%2C%22Europa%22%5D%2C%22Saturn%22%3A%5B%22Titan%22%2C%22Rhea%22%2C%22Iapetus%22%2C%22Dione%22%2C%22Tethys%22%2C%22Enceladus%22%5D%2C%22Uranus%22%3A%5B%22Titania%22%2C%22Oberon%22%2C%22Umbriel%22%2C%22Ariel%22%2C%22Miranda%22%5D%2C%22Neptune%22%3A%5B%22Triton%22%2C%22Proteus%22%5D%2C%22Pluto%22%3A%5B%22Charon%22%2C%22Hydra%22%2C%22Nix%22%5D%7D%0Aplanets%20%3D%20Object%2Ekeys%28planetData%29%0Aplanets%2EforEach%28function%28planet%29%7B%0A%09row%20%3D%20rootItem%2EaddChild%28%0A%09%09null%2C%0A%09%09function%28child%29%7Bchild%2Etopic%20%3D%20planet%7D%0A%09%29%0A%09moons%20%3D%20planetData%5Bplanet%5D%0A%09moons%2EforEach%28function%28moon%29%7B%0A%09%09row%2EaddChild%28%29%2Etopic%20%3D%20moon%0A%09%7D%29%0A%7D%29

 1  Source Object • The data source for our outline is a JavaScript object containing other objects, each of which contains an array of the names of the larger moons of the planet whose name is used as the key for the object.

 2  Object Keys • Using the keys() method for the Object class to extract the keys for the objects within the main object. In this case, the keys are unique and are the names of the planets. The result is an array of their names matching the order of the secondary objects.

 3-12  forEach() method • Iterating the array of keys (planet names), passing-through the name of a planet with each iteration.

 4-7  addItem() method • Creating a new child of the rootItem and assigning its value to be the name of the planet.

 8  key/value • Using the passed-through planet name as the key for retrieving the value from the corresponding secondary object of the main data object. The retrieved value is an array of the names of the important moons of the planet.

 9-11  forEach() method • Iterating the array of moon names to create and set new children for each of the moons. Note, if the moons array is empty ([]) no items (children) are added.

DO THIS ►

Copy and paste the previous script into the console window, and execute it by pressing the Return key.

The result of the script will be the multi-level outline shown below. (I’ve expanded two of the top-level items to reveal their children.)

planets-and-moons--01

Array of Keyed Objects

There’s another type of data structure that’s commonly used with JavaScript, and that is an Array of Keyed Objects.

But before examining the new data structure, let’s clear the content from the outline document.

DO THIS ►

Copy and paste the following script into the console window, and execute it by pressing the Return key.

rootItem.children.forEach(function(child){child.remove()})
omnioutliner:///omnijs-run?script=rootItem%2Echildren%2EforEach%28function%28child%29%7Bchild%2Eremove%28%29%7D%29

In the following example, the parent container in an array that contains multiple objects that implement the key/value design. In this example, each object utilizes the same two keys: “planet” and “moons”. The corresponding value for the “planet” key is the name of the planet, and the corresponding value for the “moons” key is an array of the names of the larger moons of the planet.

planetData = [{"planet":"Mercury","moons":[]},{"planet":"Venus","moons":[]},{"planet":"Earth","moons":["Moon"]},{"planet":"Mars","moons":["Deimos", "Phobos"]},{"planet":"Jupiter","moons":["Ganymede","Callisto","Io","Europa"]},{"planet":"Saturn","moons":["Titan","Rhea","Iapetus","Dione","Tethys","Enceladus"]},{"planet":"Uranus","moons":["Titania","Oberon","Umbriel","Ariel","Miranda"]},{"planet":"Neptune","moons":["Triton",""]},{"planet":"Pluto","moons":["Charon","Hydra","Nix"]}] planetData.forEach(function(dataObject){ planet = dataObject['planet'] moons = dataObject['moons'] row = rootItem.addChild( null, function(child){child.topic = planet} ) moons.forEach(function(moon){ row.addChild().topic = moon }) })
omnioutliner:///omnijs-run?script=planetData%20%3D%20%5B%7B%22planet%22%3A%22Mercury%22%2C%22moons%22%3A%5B%5D%7D%2C%7B%22planet%22%3A%22Venus%22%2C%22moons%22%3A%5B%5D%7D%2C%7B%22planet%22%3A%22Earth%22%2C%22moons%22%3A%5B%22Moon%22%5D%7D%2C%7B%22planet%22%3A%22Mars%22%2C%22moons%22%3A%5B%22Deimos%22%2C%20%22Phobos%22%5D%7D%2C%7B%22planet%22%3A%22Jupiter%22%2C%22moons%22%3A%5B%22Ganymede%22%2C%22Callisto%22%2C%22Io%22%2C%22Europa%22%5D%7D%2C%7B%22planet%22%3A%22Saturn%22%2C%22moons%22%3A%5B%22Titan%22%2C%22Rhea%22%2C%22Iapetus%22%2C%22Dione%22%2C%22Tethys%22%2C%22Enceladus%22%5D%7D%2C%7B%22planet%22%3A%22Uranus%22%2C%22moons%22%3A%5B%22Titania%22%2C%22Oberon%22%2C%22Umbriel%22%2C%22Ariel%22%2C%22Miranda%22%5D%7D%2C%7B%22planet%22%3A%22Neptune%22%2C%22moons%22%3A%5B%22Triton%22%2C%22%22%5D%7D%2C%7B%22planet%22%3A%22Pluto%22%2C%22moons%22%3A%5B%22Charon%22%2C%22Hydra%22%2C%22Nix%22%5D%7D%5D%0AplanetData%2EforEach%28function%28dataObject%29%7B%0A%09planet%20%3D%20dataObject%5B%27planet%27%5D%0A%09moons%20%3D%20dataObject%5B%27moons%27%5D%0A%09row%20%3D%20rootItem%2EaddChild%28%0A%09%09null%2C%0A%09%09function%28child%29%7Bchild%2Etopic%20%3D%20planet%7D%0A%09%29%0A%09moons%2EforEach%28function%28moon%29%7B%0A%09%09row%2EaddChild%28%29%2Etopic%20%3D%20moon%0A%09%7D%29%0A%7D%29

 1  Source Data • An array of keyed objects, with each object using the same two keys: planet and moons.

 2-12  forEach() method • Iterating the array of keyed objects with each iteration passing through one of the data objects.

 3  planet data • Use the key “planet” to retrieve and store the name of planet object being processed.

 4  moons data • Use the key “moons” to retrieve and store an array of the names of the moons of the planet object being processed.

 5-8  create and set item • Create a new outline row and set its value to the name of the planet.

 9-11  forEach() method • Iterate the list of moons, creating children (if needed) for the new row.

DO THIS ►

Copy and paste the previous script into the console window, and execute it by pressing the Return key.

The result of the script will be the multi-level outline shown below. (I’ve expanded two of the top-level items to reveal their children.)

planets-and-moons--01

The three shown data-parsing techniques (aligned arrays, data object, and object array) produce the same result of a multi-level outline, regardless of the technique used to store the data.

Summary

In this section you’ve learned how to create and remove items from an outline using the rootItem object and the addChild() and forEach() methods. In creating outlines you’ve parsed JavaScript arrays and objects with key/value pairs. Many of the scripts you write for yourself will incorporate the techniques demonstrated in this section.

What’s Next?

In the next section, we’ll examine how to use the Editor class to manipulate the items in an outline document.

UNDER CONSTRUCTION

This webpage is in the process of being developed. Any content may change and may not be accurate or complete at this time.

DISCLAIMER