The anatomy of a cog

For the IGWEB project, we will be creating cogs in the $IGWEB_APP_ROOT/shared/cogs folder. You can take a peek at the time ago cog, whose implementation is found in the $IGWEB_APP_ROOT/shared/cogs/timeago folder, as you read through this section, to see a tangible implementation of the concepts presented herein. 

For the purposes of illustration only, we are going to walk you through the process of creating a simple cog called widget.

The project structure for the widget cog contained within the widget folder is organized in the following manner:

  ⁃ widget
⁃ widget.go
⁃ templates
⁃ widget.tmpl

The widget.go source file will contain the implementation for the widget cog.

The templates folder contains the template source file(s) used to implement the cog. If the cog is to be rendered on the web page, at least one template source file must be present. The template source file's name must match the package name of the cog. For example, for the cog package widget, the name of the template source file must be widget.tmpl.

Cogs follow a convention over configuration strategy when it comes to naming package names and source files. Since we have chosen the name widget we must declare a Go package named widget as well inside the widget.go source file:

package widget

All cogs are required to include the errors package, the reflect package, and the cog package in their import grouping:

import (
"errors"
"reflect"
"github.com/uxtoolkit/cog"
)

We must declare an un-exported, package scoped variable called cogType:

var cogType reflect.Type

This variable represents the cog's type. We call the TypeOf function in the reflect package, passing in a newly created instance of the cog, to dynamically set the cog's type inside the cog package's init function:

func init() {
cogType = reflect.TypeOf(Widget{})
}

This provides a hook for isokit's static bundling system, to know where to look, to obtain the static assets required to make a cog function.

A cog implements a specific type. In the case of a widget, we implement the Widget type. Here's the Widget struct:

type Widget struct {
cog.UXCog
}

We must type embed the cog.UXCog type to bring all the functionality needed from the cog.UxCog type in order to implement the cog.

The struct may contain other field definitions that are required to implement the cog, depending on the purpose that the cog serves.

Every cog implementation should include a constructor function:

func NewWidget() *Widget {
w := &Widget{}
w.SetCogType(cogType)
return f
}

As with any typical constructor function, the purpose is to create a new instance of the cog, Widget.

The cog's constructor function must contain the line that calls the SetCogType method (shown in bold). This is used as a hook by isokit's automatic static assets bundling system to bundle the cog's required static assets.

Additional fields of the Widget type may be set to initialize the cog based on the cog's implementation.

In order to fulfill the implementation of the Cog interface, all cogs must implement a Start method:

func (w *Widget) Start() error {

var allRequiredConditionsHaveBeenMet bool = true

The Start method is responsible for activating the cog, which includes the initial render of the cog to the web page. The Start method will return an error object, if the cog failed to start, otherwise, a nil value will be returned.

For illustration purposes, we have defined an if conditional block containing a Boolean variable called allRequiredConditionsHaveBeenMet:

  if allRequiredConditionsHaveBeenMet == false {
return errors.New("Failed to meet all requirements, cog failed to start!")
}

If all the conditions to start the cog have been met, this variable will be equal to true. Otherwise, it will be equal to false. If it is false, then we will return a new error object, indicating that the cog was unable to start since all requirements had not been met.

We can set a key-value pair in a cog's Props map by calling the SetProp method:

  w.SetProp("foo", "bar")

In this case, we have set the prop named foo to the value bar. The Props map will automatically be used as the data object that gets fed into a cog's template. This means that all props defined in the Props map are accessible by the cog's template.

The cog's template source file name, by convention, must be named widget.tmpl to match the cog's package name of widget, and the template file should reside in the templates folder, which is located in the cog's folder, widget.

Let's take a quick look at what the widget.tmpl source file may look like:

<p>Value of Foo is: {{.foo}}</p>

Notice that we are able to print out the value of the prop that has a key of foo within the template.

Let's return back to the widget cog's Start method. We call the cog's Render method to render the cog in the web browser:

  err := w.Render()
if err != nil {
return err
}

The Render method returns an error object if an error was encountered while rendering a cog, otherwise it will return a value of nil to indicate that the cog was rendered successfully.

If the cog was rendered successfully, the cog's Start method returns a value of nil to indicate that the cog has been started successfully:

return nil

In order to render our cog to the real DOM, we need a place to render the cog to. The div container that houses the rendered content of a cog is known as its mount point. The mount point is where the cog gets rendered to in the DOM. To render the widget cog on the home page, we would add the following markup to the home page's content template:

<div data-component="cog" id="widgetContainer"></div>

By setting the data-component attribute to "cog", we indicate that the div element is meant to be used as a cog's mount point, and the cog's rendered content will be contained inside this element.

In the client-side application, the widget cog can be instantiated like so:

w := widget.NewWidget()
w.CogInit(env.TemplateSet)
w.SetID("widgetContainer")
w.Start()
w.SetProp("foo", "bar2")

We create a new Widget instance and assign it to the variable w. We must call the CogInit method of the cog to associate the application's TemplateSet object with the cog. The cog utilizes the TemplateSet so that it may fetch it's associated template(s), which are required to render the cog. We call the cog's SetID method, passing in the id to the div element that acts as the cog's mount point. We call the cog's Start method to activate the cog. Since the Start method calls the cog's Render method, the cog will be rendered in the designated mount point, the div element with id, "widgetContainer". Finally, when we call the SetProp method and change the value of the "foo" prop to "bar2", the cog will get re-rendered automatically.

Now that we've examined the basic anatomy of a cog, let's consider how cogs are rendered using a virtual DOM.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.181.57