Category Filtering: 'altseven'

Livesandbox Web app editor v 0.11.0

altseven, JavaScript, Open Source

Good news for open source JavaScript supporters- the livesandbox project is nearing a 1.0.0 release. I have added some of the missing features in the beta roadmap. You can see the project on it GitHub page.

Updates in this release:

  • add notifications on save and delete of apps and libraries
  • add confirmation dialogs when abandoning changes in apps and libraries
  • update database to change JS, CSS, and HTML fields to text from varchar to accommodate larger projects
  • update to altseven remote module to return promises from invoked remote methods so promises can be handled from calling code

These changes bring the editing experience closer to what developers (certainly myself) would expect to see in an editor application.

For a v 1.0.0 release, I expect to add a user profile page. I am also considering making public (anonymous) access part of the release. An admin system and multi-user access (viewing applications of other users) may also be part of the release, though I have not scoped these features and am not yet ready to commit to making them part of the release.


Livesandbox Web app editor v 0.9.4

altseven, JavaScript, Open Source, Web Development

Another update of the livesandbox editor is available on GitHub. I made some important fixes to the application and wanted get this code released as soon as possible.

Updates in this release.

  • fix update/read issues with saving apps
  • change editor layout
  • fix sometimes incorrect saving of esModule bit field
  • fix save/retrieval/loading of app libraries
  • add getApps and getLibraries stored procedures to git
  • update db dump
  • set editor to wrap long lines so the editor width does not grow beyond 50% of sandbox width

Upgrading from previous releases:

In addition to pulling the latest master (or the 0.9.4 tag) from GitHub, you will need to update the getApps stored procedure in the database. A SQL script has been added to ./database/getApps.sql with the updated stored procedure code. You can, if you prefer, simply replace the previous database with the new backup in the ./database folder.

The application is getting closer to being stable and feature complete for a 1.0.0 release. Outstanding tasks:

  • add notifications on successful save/delete of apps and libraries
  • add warnings when discarding unsaved changes
  • add paging for apps and libraries lists

I may or may not add an admin feature as part of the 1.0.0 release.


Iterative Development as Software Craft

altseven, Health & Science, Open Source, Web Development

Background

The practice of software is part engineering and part craft. Academia is full of coursework designed to teach you the theory of computing and the engineering discipline of writing software. Learning software as a craft, though, seems to occur over time in the profession of software development.

Iteration as a process for software development, in my mind, has always belonged in the realm of "software as craft" rather than "software as engineering discipline". Granted, there is plenty of room to look at iteration as part of an engineering process, but I relate it to how writers of novels build a story and refine the story over a series of drafts until they arrive at a completed work.

My approach to software development has always been to build a working skeleton of an application and then refine and expand it over time using an iterative approach. I'm going to share, briefly, the why and how of my approach.

Iterative Development as Craft

Building complex software systems is hard. If you've worked in the field for a few years, you've probably had more than your share of frustrations during a complex software project where careful planning went into the requirements gathering and specification phase, only to have some significant aspect of the specification change midway through the project. These kinds of failures (yes, they are failures, though individually they might not doom an entire project) have become less common through the use of iterative software development.

Instead of trying to build every aspect of a software system in a single pass, iterative development encourages you to build a skeleton of functionality for the application, prove that it works, then layer in additional functionality in successive passes. The craft of iterative development begins with understanding how much you can build in a single iteration without compromising a primary goal of iterative development - building in small chunks to simplify the testing and debugging phase of each iteration. Knowing how much you can take on in a single pass requires enough experience to be familiar with the pace of development and the complexity of debugging for a given system.

By using source control and building iteratively, you can provide yourself with a history that shows in time how your application has developed over a series of iterations. On GitHub, I use semver and tags to mark my progress.

Iterative Development v. Versions

Speaking of semver, you might object, "But you are really talking about versions. Every software company since forever has made successive versions of their products/projects." In a sense, that's true, versions are a long version of iterative development. When I refer to iteration, though, I'm really talking about the process of iterating within the development process, though what that means may be a little fuzzy. In the tasklist altseven sample app, I have been slowly building more complexity into the application over a period of time to demonstrate how the altseven framework has been evolving. You can go to the repos for both projects and see the snapshots (as tags) at each step along the way. When I think of iterative development within a single version, what I am referring to is building in passes to get to a pre-defined end state. Version development (which you can see more clearly in the building of altseven) involves building new features with each successive pass.

Iteration as Exploration

Not too long ago, Kyle Simpson (@getify of You Don't Know JavaScript fame) pondered about having a tool for realtime execution of JavaScript - browser-based - other than the browser console. I took on the challenge to build something useful as quickly as possible. With only the barest of specs, I built a very simple mechanism to execute JavaScript from a Web page. Over a few iterations, I slowly built it into something that, while still very much a prototype, more fully meets the initial functional requirements that Kyle was looking for. You can see it for yourself at https://github.com/robertdmunn/livesandbox. It is still very much a prototype, but it has features that make it useful if you need a simple scratchpad for JavaScript code.

Iteration Within a Single Task

Even within individual version development projects, you may have isolated tasks that benefit from an iterative process. Recently, I completed a two year consulting project that involved converting large chunks of a twenty-ish year old codebase into a new framework in the same language (CFML). If you've never taken on a project like that, you might immediately think about writing some sort of parser to read in the old code and generate output code in the new framework. While that might work in certain projects, in this particular project I felt like there was no payoff for trying to write a proper parser for old CFML. Instead, I used an iterative process where I slowly ported individual pieces of code into the new framework, tested that they worked, and made successive passes at the code until I had ported the entire chunk of functionality.

One aspect of this particular task involved porting tag-based CFML code to cfscript, the ECMA-compliant script version of CFML. I have found that a series of passes using regular expressions inside a text editor/IDE can be used to convert a lot of CFML code to cfscript with very little hassle. Because of the nature of the old codebase, this approach made far more sense than trying to write a very complex parser to read in the old code base and try to output something useful for the new framework.

 

In Conclusion

I hope that I have helped you understand, in at least some minimal detail, both the motivations and the strategies behind iterative development. Going into more detail requires digging into code and showing real world examples, and might require a book length discussion to provide useful insight into the details of the process.


Tasklist altseven example app - updated v. 0.3.0

altseven, JavaScript

There is an update to the Tasklist altseven example application, and it's awesome. A few notes on what I have updated:

  • Implemented AOP for tasks and users
  • replaced sha.js with bcrypt for passwords
  • changed db users.password to users.hash char(60)
  • fixed token generation
  • replace mysql driver with official maradb driver
  • modified dao/gateway code for MariaDB driver support

In the next day or so I will do a deep dive into code changes on the server side. The biggest changes are switching the mysql driver for the mariadb driver and fully implementing secured routes with tiny-aop.

You can grab the source code for tasklist from Github:

https://github.com/robertdmunn/tasklist

 


The Altseven View Component and the Rendering Queue in 3.2.x

altseven, JavaScript, NodeJS, Open Source

As of altseven 3.2.x, I have made some changes to the way view components listen for changes and register for rendering with the render queue. The first changes come in the config() function inside the View component. The bubbling of mustRender events from child to parent has been removed. The render queue now tracks what components are being rendered and ensures that parent views are rendered before their children.

As a result, the setState() function in the View component now fires the mustRender event for all views, and the mustRender handler add the view to the queue.

setState: function( args ){
    this.state = args;
    // setting state requires a re-render
    this.fireEvent( 'mustRender' );
},

and the mustRender event handler, which now queues views for rendering:

this.on( "mustRender", function(){
    a7.ui.enqueueForRender( this.props.id );
}.bind( this ));

 

Essentially, the complexity of managing the rendering queue has largely been moved from the View component to the a7.ui component. Let's look at the enqueueForRender method. As with other methods in components in altseven, enqueueForRender references an internal component method, _enqueueForRender:

_enqueueForRender = function( id ){
  if( ! _stateTransition ){
    a7.log.info( 'enqueue: ' + id );
    if( ! _queue.length ){
      a7.log.trace( 'add first view to queue: ' + id );
      _queue.push( id );
      // wait for other possible updates and then process the queue
      setTimeout( _processRenderQueue, 18 );
    }else{
      let childIds = _getChildViewIds( id );
      if( _views[ id ].props.parentID === undefined ){
        // if the view is a root view, it should be pushed to the front of the stack
        a7.log.trace( 'add to front of queue: ' + id );
        _queue.unshift( id );
      }else{
        let parentIds = _getParentViewIds( id );

        let highParent = undefined;
        if( parentIds.length ){
          highParent = parentIds.find( function( parentId ){
            return _queue.indexOf( parentId ) >= 0;
          });
        }

        // only add if there is no parent in the queue, since parents will render children
        if( highParent === undefined ){

          a7.log.trace( 'add to end of queue: ' + id );
          _queue.push( id );
        }
      }

      // remove child views from the queue, they will be rendered by the parents
      childIds.forEach( function( childId ){
        if( _queue.indexOf( childId ) >= 0 ){
          a7.log.trace( 'remove child from queue: ' + childId );
          _queue.splice( _queue.indexOf( childId ), 1 );
        }
      });
    }
  }else{
    _deferred.push( id );
  }
},

First, let's see what variables we're using, and what they are doing. We have _stateTransition, which is a boolean value that tracks whether the current queue is rendering. If the queue is not rendering, the process will look to add the requested view to the queue, which is held in an array of string IDs in a variable called _queue. If the current queue is rendering, the view ID is instead added to another Array called _deferred. Once the current queue is rendered, _queue will be emptied and the IDs in _deferred will be added to _queue.

Next we have childIds, which holds an array of IDs of all child views of the current view being processed. The function uses this array to remove any child views of the current view from the rendering queue. Since parents render their own children by default using the rendered event handler, we don't want the children in the render queue or they will be rendered more than once.

We also have parentIds, which as you might expect holds an array of view IDs for the parents of the current view being processed, and highParent, which is the highest parent view in the chain of parentIds. We use these values in conjunction to verify that we do not add views to the queue if the view has a parent already in the queue. As with childIds, we only want to add the highest level view in a given subtree to the queue; we'll leave child view rendering to the rendered event handler.

_getChildViewIds and _getParentViewIds are functions that the enqueueForRender function calls to return these child and parent view ID arrays. Like much of the newest functionality in altseven, these functions do their jobs, but they are not optimized or expected to be particularly efficient. I don't expect deep nesting of view components in altseven apps, so I don't see optimization as a particular priority in this case.

As you can see at the beginning of the function, if the _queue.length property is 0, the function adds the view ID as the first element of _queue and then schedules the queued to be processed using setTimeout(). It leaves just enough time ( 18 ms ) for related views to register themselves for rendering as needed.

Processing the Rendering Queue

Let's look at _processRenderQueue.

    _processRenderQueue = function(){
      a7.log.trace( 'processing the queue' );
      _stateTransition = true;

      _queue.forEach( function( id ){
          _views[ id ].render();
      });
      _queue = [];
      _stateTransition = false;
      _deferred.forEach( function( id ){
        _enqueueForRender( id );
      });
      _deferred = [];
    },

Once the setTimeout function fires _processRenderQueue sets _stateTransition to true, which signals to _enqueueForRender that it should queue requested updates in the _deferred queue. It then iterates through _queue and calls the render() function for the given view ID in _views. What is significant here is that the array of views in _views is the original array that was registered by a7.ui.register(). Altseven works by registering all the views in the application, which places the views in this _views array for the duration of the application. Views are always referenced by this variable, which can be called outside the a7.ui component using the property a7.ui.views. Unlike early iterations of the framework, altseven 3.2.x does not pass views around or attempt to copy them. Once they are in a7.ui.views, that's where they stay until they are destroyed.

 

 


Embracing ReactJS-style UI rendering in altseven with ES6 Template Literals - Part III

altseven, JavaScript, NodeJS, Open Source

Update

------------

Parts of this post are no longer accurate, as altseven 3.2.x has changed the way components queue for rendering. See The Altseven View Component and the Rendering Queue in 3.2.x for updated information about the rendering queue.

------------

 

I first started building the altseven JavaScript framework in order to bring together various bits of functionality that I had built for earlier applications. I started with some general ideas about how I wanted to do things and a few tools in my toolbox with which to do them.

The Constructor

I had previously built a component to create objects in a consistent way, and I wanted to use its ability to bind custom events to created objects in altseven. The component creates objects using a given prototype and Object.create. It then assigns custom event handlers to the created object based on the object prototype. Let's look at the Constructor function:

function Constructor( constructor, args, addBindings ) {
	var returnedObj,
		obj;

	// add bindings for custom events
	// this section pulls the bindings ( on, off, fireEvent ) from the
	// EventBindings object and add them to the object being instantiated
	if( addBindings === true ){
		//bindings = EventBindings.getAll();
 		EventBindings.getAll().forEach( function( binding ){
			if( constructor.prototype[ binding ] === undefined ) {
				constructor.prototype[ binding.name ] = binding.func;
			}
		});
	}

	// construct the object
	obj = Object.create( constructor.prototype );

	// this section adds any events specified in the prototype as events of
	// the object being instantiated
	// you can then trigger an event from the object by calling:
	// <object>.fireEvent( eventName, args );
	// args can be anything you want to send with the event
	// you can then listen for these events using .on( eventName, function(){});
	// <object>.on( eventName, function(){ })
	if( addBindings === true ){
		// create specified event list from prototype
		obj.events = {};
		if( constructor.prototype.events !== undefined ){
			constructor.prototype.events.forEach( function( event ){
				obj.events[ event ] = [ ];
			});
		}
	}

	returnedObj = constructor.apply( obj, args );
	if( returnedObj === undefined ){
		returnedObj = obj;
	}
	//returnedObj.prototype = constructor.prototype;
	return returnedObj;
}

The Constructor function pulls the methods from the EventBindings mixin object. ( The mixin provides for a way to assign the methods of one object to an arbitrary object or prototype ). Next, if the given prototype has an array of events defined, the Constructor assigns those events to the generated object as bindable events.

When the Constructor is done, it returns an object with the methods and properties of the prototype, the on(), off(), and fireEvent() methods of the EventBindings mixin, and bindable events listed in the object prototype.

The View function

As of v. 3.x of altseven, the View function, which provides the base for rendered UI elements in altseven, has been expanded to handle some of the functionality that was centralized in the a7.ui.setView() method. The events for the View function:

events : ['mustRender','rendered', 'mustRegister', 'registered']

provide hooks for registering and rendering components, as well as hooks to execute functions when registration and rendering finish. View now has a prototype method called config that registers event handlers for these events:

	config: function(){

		this.on( "mustRegister", function( parent ){
			this.props.parentID = parent.props.id;
			a7.ui.register( this );
		}.bind( this ) );

		this.on( "mustRender", function(){
			// only render root views from here, children will be rendered by parents through bubbling of events
			if( this.props.parentID === undefined ){
				this.render();
			}
		}.bind( this ));

		this.on( "rendered", function(){
			this.onRendered();
		}.bind( this ));

		this.on( "registered", function(){
			// register children
			if( this.props !== undefined ){
				for( var prop in this.props ){
					if( this.props[ prop ] !== null && this.props[ prop ].type !== undefined && this.props[ prop ].type === "View" ){
						if( a7.ui.getView( this.props[ prop ].props.id ) === undefined ){
							this.props[ prop ].fireEvent( "mustRegister", this);
						}
					}
				}
			}
			if( this.props.parentID === undefined ){
				// only fire render event for root views, children will render in the chain
				this.fireEvent( "mustRender" );
			}
		}.bind( this ));

		// bubble up event
		if( this.props !== undefined ){
			for( var prop in this.props ){
				if( this.props[ prop ].type !== undefined && this.props[ prop ].type === 'View' ){
					this.props[ prop ].on( "mustRender", function(){
						this.fireEvent( "mustRender" );
					}.bind( this ));
				}
			}
		}
	},

We have four event handlers in the config() function corresponding to our four events- mustRegister, mustRender, registered, and rendered. I've thought about making views self-registering, so every view, when instantiated, would fire mustRegister. At the moment, views in the root of a DOM subtree  (those with no parents in altseven) must be registered manually, while children of root views are registered automatically when the root view handles the registered event, as you can see above. I am assigning a parentID to child views in each DOM subtree.

But isn't that a virtual DOM? I don't think it qualifies, at least not quite yet. I'm keeping track of each view, it's HTMLElement, and its parent. If I add a render queue, I should probably start keeping track of whether state is dirty or not. Does that make it a virtual DOM? I'm not getting stuck on semantics ...

Looking at the event handlers, you might notice that only root views actually call this.render() inside the mustRender event handler. Child views are handled elsewhere because they need the rendered HTML from the parent to exist in order for their selectors to return an HTMLElement using document.querySelector(). They are handled inside the onRendered() function, which is called from the rendered event handler.

You might also notice that the registered event handler fires mustRender for root views. It doesn't need to fire it for child views; remember, they are rendered in turn by their parents.

The last thing to notice is the note about bubbling up events. Parent views are bound to the mustRender events of their children, and they in turn fire a mustRender event. The net effect of this bubbling is that a mustRender event fired in the lowest child view will bubble up and eventually fire the root view in the chain. If you are familiar with React, you'll understand why React uses a rendering queue to enhance performance.

Without any changes to this code, every event in a DOM subtree is going to re-render the entire subtree. That might not matter in a small application, but in a large one it could create significant performance issues. Adding a rendering queue would allow us to check if a render process is already queued and if so whether there are duplicates being queued and in what order they should be called.

OK, so it looks a lot more like a virtual DOM with those features. I'm still not getting stuck on semantics.

Nested Rendering

The last thing I want to do for this post is show the onRendered() function.

	onRendered: function(){
		if( this.props !== undefined ){
			for( var prop in this.props ){
				if( this.props[ prop ].type !== undefined && this.props[ prop ].type === "View" ){
					this.props[ prop ].props.element = document.querySelector( this.props[ prop ].props.selector );
					this.props[ prop ].render();
				}
			}
		}
	}

What this bit of code does is to loop through the props of a view to see if there are any child views. If there are, it pulls the HTML element from the DOM using the cached selector string. Remember, we need to wait until this point to guarantee that the selector, when queried, will pull an element. It then calls the child view's render() function, which in turns will run this code again to check for children and render them as well.

That's it for now. As you might have guessed, I'm working on the rendering queue to improve performance and eliminate duplicate rendering. Watch my Twitter feed (@robertdmunn) for news about the next iteration of the altseven codebase.


Setting up and Running the Tasklist altseven example app

altseven, JavaScript, NodeJS, Open Source

Since I am covering the tasklist application in some detail, I'd like to walk you through the process of setting it up so you can run it yourself.

 

1. Clone from GitHub

$ cd ~/git
$ git clone https://github.com/robertdmunn/tasklist
$ cd tasklist

I like to put my git repos in a folder called (you guessed it) git inside my home folder. Clone the repo to whatever location works for you. Once you have cloned the repo, you should see something like this in the ./tasklist folder:

 

2. Create the database

The database is pretty simple- two tables in MySQL or MariaDB. You'll need a copy of one of them running somewhere to proceed.

Create an empty database in your db server. Call it whatever you like. I use UTF-8 collation as standard practice.

Open the database folder and open the script.sql file inside it. Execute that script against the database you just created. You should end up with two tables in your database. Create a username and password to access the database.

From the command line, run:

$ node hashpassword.js

Copy the console output into a command to update the password for your user in the users table:

$ update users set password = '<hash_value>' where userID = 1;

 

3. Modify the configuration

Open the config folder. Open the dbconfig.js file in a text editor. It should look like this:


var mysql = require( 'mysql' );

const pool = mysql.createPool({
  connectionLimit : 50,
  host            : 'localhost',
  user            : 'root',
  password        : 'password',
  database        : 'project_master'
});

module.exports = {
  pool: pool
};

Modify the host, user, password, and database values to match your environment.

 

4. Install dependencies

Go to the command line inside the ./tasklist folder. Install the npm dependencies, and then (optionally) install Bower dependencies.

$ npm install
$ bower install

 

Pre-requisites:

You will need Bower and npm installed and configured on your system. Check npm for instructions on installing npm in your OS. Once you have npm installed, get Bower:

$ npm install -g bower

 

5. Run the app

Once you have everything installed, you should be able to type:

$ node index.js

in the root of ./tasklist, then open the home page in your browser:

http://127.0.0.1:4000/

You should see something like this:

The Console Window on the right show debugging information from the altseven framework. You can use a7.log.(info|trace|error|fatal|warn)(message) to log information to this console in your application. There isn't much set up in the tasklist app, so mostly you will see the altseven framework debugging information. Later on I might add server-side logging to push to the console to demonstrate how that works.

Log in with the provided user and password. If the login fails, check your users table in the database to be sure the default user was inserted by the database script.

When you login, you should see something like this:

Add some entries. You should now see your tasks on the screen:

That's it! You should be able to complete and delete tasks as well. Give it a try and see what happens.

This app shows you how to build something small but useful in altseven using NodeJS as a back end. The client side application, apart from dependencies, is 500 lines long.


Embracing ReactJS-style UI rendering in altseven with ES6 Template Literals - Part II

altseven, JavaScript, NodeJS, Open Source

Eighteen days seems like forever in the Internet age. It was only eighteen days ago that I wrote Part I of this article about challenges solving some problems with building a React-style rendering solution in the altseven JavaScript framework. I promised to blog again about solutions to some of these challenges that I created in altseven v 1.20. Well, eighteen days and two additional versions of altseven later, I've solved all of the challenges I wanted to solve and added some useful new features to the framework.

Event Handlers

The first challenge I faced was to add event handlers to ES6 template literals and have them bind to the DOM when rendered. The key there is that you have to wait until the template literal is rendered into the DOM to bind the events. Once I realized that bit of truth, it was easy enough to devise a means of writing event handlers that could be bound after rendering. Let's look at a Header component written using ES6 template literals:

    function Header(props) {
      var header = a7.components.Constructor(a7.components.View, [props], true);

      header.state = {
        user: props.user
      };

      header.eventHandlers = {
	  logout: function(){
            a7.events.publish( 'auth.logout', { callback: app.auth.authenticate }) ;
	  }
	};

      header.template = function(){
		return `Welcome, ${Setting: header.state.user.firstName not found} <a name="signout" data-onclick="logout">[ Sign out ]</a>`;
	};

      return header;
    }

As a reminder, I'm using Douglas Crockford's method of stuffing a function's prototype methods into another object using a constructor function. From there, I create the initial state of the object. Then we see a couple of new methods and the removal of another. header.eventHandlers is an object with named keys of functions that respond to events in the template literal. In this case, I have a logout function that responds to the click event in header link.

However, because we're dealing with a template literal and not an actual rendered DOM node ( yet ), I can't just bind the handler to the event. Instead, and in order to stay compliant with standard HTML and JavaScript ( one of my keys goals ), I have added a "data-onclick" attribute to the <a name="signout"> link. When the view renders, a process will examine all the "data-on" attributes in the rendered HTML and bind the event handlers to the corresponding elements. Did you notice that render() is what was missing from the Header function? The View component now houses the render function, and that's where a lot of action occurs. Let's look at it:

	render: function(){
		if( this.props.element === undefined || this.props.element === null ){
			this.props.element = document.querySelector( this.props.selector );
		}
		if( !this.props.element ) throw( "You must define a selector for the view." );
		this.props.element.innerHTML = ( typeof this.template == "function" ? this.template() : this.template );

		var eventArr = [];
		a7.ui.getEvents().forEach( function( eve ){
			eventArr.push("[data-on" + eve + "]");
		});
		var eles = this.props.element.querySelectorAll( eventArr.toString() );

		eles.forEach( function( sel ){
			for( var ix=0; ix < sel.attributes.length; ix++ ){
				var attribute = sel.attributes[ix];
				if( attribute.name.startsWith( "data-on" ) ){
					var event = attribute.name.substring( 7, attribute.name.length );
					sel.addEventListener( event, this.eventHandlers[ sel.attributes["data-on" + event].value ] );
				}
			}
		}.bind( this ));

		this.fireEvent( "rendered" );
	}

I'll gloss over the section that sets the rendered HTML for now. After it gets set, the function iterates over a7.ui.getEvents() to build a long (very long) query selector that pulls all elements with data-on* attributes from the rendered HTML. By default, a7.us.getEvents() contains a list of all standard DOM events listed on the Mozilla Developer Network browser Events page. Since most applications will only use a fraction of those events, you can set an array of only the events used in your application in the altseven configuration object. Doing so will improve performance in your application.

Once the elements are pulled into the eles variable, the function iterates over the elements and then loops over its attributes looking for data-on* attributes. While nested looping isn't ideal, it gets the job done. An improvement to this process, if possible, would be good for performance, especially on HTML like rendered lists of data with click handlers on each row/cell.

When the function finds a data-on* attribute, it checks the value of the attribute against eventHandler keys in the created object. If there is a match, it adds a listener for the event and sets the handler to the proper eventHandler function.

Going back to the Header object, you can see in the eventHandlers.logout function that, because the function is defined inside the Header object, it has access to the a7 namespace and the app namespace (the namespace of the application). Although it isn't used in this example, it also has access to the object namespace, in this case header. Also not listed, since logout is an event handler, it could be written as:

logout: function( event )

Since the event will be passed to the handler by the browser, giving us access to the Event object as well.

By writing the event handlers inline but deferring binding them to the DOM until we know the HTML for the object is rendered - we can write our functions using standard syntax and scopes and still be guaranteed that they will be available in the rendered HTML.

I hedged about using data-on* attributes to hold the values of the eventHandlers required for a given element, but ultimately, I decided that, since it met my goal of using standard HTML and Javascript, it would be an acceptable solution.

In Part III, I will go over how altseven v. 3.x uses events to automate several processes including rendering on state change.


Embracing ReactJS-style UI rendering in altseven with ES6 Template Literals - Part I

altseven, CommandBox, JavaScript, Web Development

I spent yesterday adding support for ES6 Template Literals as an alternative to Mustache/Handlebars. It works well and obviates the need for a templating framework in your project. However, I got stuck when I decided to modify the UI rendering functionality. I am trying to make it more ReactJS-like, but without a compile step or a virtual DOM.


Categories


Recent Entries

Entries Search