@superherocheesecake/superherojs-superhero-js
v1.7.3
Published
``` _____ _ _ _____ / ____| | | | |/ ____| | (___ _ _ _ __ ___ _ __| |__ ___ _ __ ___ | | (___ \___ \| | | | '_ \ / _ \ '__| '_ \ / _ \ '__/ _
Downloads
3
Readme
_____ _ _ _____
/ ____| | | | |/ ____|
| (___ _ _ _ __ ___ _ __| |__ ___ _ __ ___ | | (___
\___ \| | | | '_ \ / _ \ '__| '_ \ / _ \ '__/ _ \ _ | |\___ \
____) | |_| | |_) | __/ | | | | | __/ | | (_) | |__| |____) |
|_____/ \__,_| .__/ \___|_| |_| |_|\___|_| \___/ \____/|_____/
| |
|_|
Superhero JS
SuperheroJS is the in-house built MVP (Model, View, Presenter) framework that we use at Superhero Cheesecake. It is built on top of Backbone, so a lot of the functionalities and API's are inherited, also some of the patterns and concepts used in SuperheroJS are borrowed from MarionetteJS.
Goals
The main goal of SuperheroJS is to provide a simple structure that helps with the most common tasks within a single page application. We want to keep SuperheroJS as lightweight as possible, so we only add functionalities to SuperheroJS that are typically used in every single project.
Features
Modules
The most basic object type in SuperheroJS is a module. Modules provide structure for 'classes' that only contain logic and are not bound to a DOM element. Modules implement the events system for easy communication with other modules and views.
Routing
The router in SuperheroJS is mostly identical to the default Backbone router. One feature that has been added is the ability to request a 'transition data' object that returns the current and previous fragment that has been navigated to. The purpose is for this to be passed to the views being rendered when a route changes so they can implement custom transitions based on previous routes.
Models and Collections
Similar to the Router, the models and collections in SuperheroJS are mostly identical to Backbone Models and Collections. With the exception that SuperheroJS Models have a build in validation function.
Store
SuperheroJS features a very simple Store module that can be used to implement an unidirectional data flow pattern. It's interface is similar to the Superhero Model, but with less functionality in favor of performance.
Supported methods are:
- get(attribute)
- set(attribute, value, [{silent:true}])
- has(attribute)
- toggle(attribute)
When an attribute value changes, a custom event will be dispatched: 'change:[attribute]'. The event payload will contain the current and previous value for the changed attribute.
More on the unidirectional data flow approach: https://www.exclamationlabs.com/blog/the-case-for-unidirectional-data-flow/
Layouts and Regions
SuperheroJS makes it very easy to switch views based on routes (or other state controllers) by instantiating views and taking care of the initialization and teardown proces. Layout views are like regular views, but can house one or more 'regions'. A region is a named container (DOM node) that can be used to render a view into. These regions are globally accessible using the Region Manager.
Defining a region within a Superhero.LayoutView is done using the regions hash:
regions: {
main: '.js-region-main' //A region called main is created and uses a DOM node with selector .js-region-main as it's container,
}
Now the Region Manager can be used to render a specific view into the region. Typically this is done whenever a route gets called in the router.
RegionManager.get('main').show(MyView); //Creates an instance of MyView and renders it into the main region.
The Region Manager and Regions handle the following:
- Check if a view is already rendered into the region. Making sure we're not rendering the same view twice.
- Creating an instance of the new view.
- Triggering sequenced transition hooks.
- Teardown of existing view.
Note: Regions are globally accessible. Make sure they all get a unique name or they will be overwritten.
Views
All SuperheroJS views extend the default Backbone view object and add some useful features to it. There are a couple of different view types that can be used:
- Component; the most basic view type. Should only be used as subview (component) of a regular view.
- View; powerful view type, mostly used for whole screens or pages.
- LayoutView; similar to the regular view, but supports regions.
Events
Backbone default functionality: TBD Note: This only works for events that bubble up. Other events need to be attached directly to the dispatching target using native addEventListener.
The UI hash
Within every SuperheroJS view a UI hash can be defined. Use this to create reusable references to DOM elements within a view. The below example shows how to select a DOM element with the classname .js-button and store it's reference under the 'myButton' key. After the view's initialization process has been completed the DOM element can be accessed using this.ui.myButton.
ui: {
myButton: '.js-button'
}
The components hash
Similar to the UI hash, but used to create components (instances of the Superhero.Component object) whenever it encounters a specific DOM element. This DOM element will then be used as the root element for the component instance. The below example shows how to select a DOM element with the classname .js-component and store it's reference under the 'myComponent' key. After the view's initialization process has been completed the component can be accessed using this.components.myComponent. You are able to pass data to your component by adding options as a third argument when the component is created.
components: {
myComponent: {selector: '.js-component', type: MyComponent, options : {
optional: true
}}
}
When a component needs arguments that are not yet available when the view is instantiated, the component can be created later on when the view is fully initialized:
onInitialized: {
addComponent: function('nameOfComponent', MyComponent, '.js-component', {optional: true});
}
The name of the component will be the name that can be used for referencing the component: this.components.nameOfComponent.
Components will be automatically disposed when the parent view is removed.
Note: The UI and components hashes will contain an array of items instead of a single reference when multiple DOM elements matching the selector are found.
Initialization queue
All views in SuperheroJS use an initialization queue, which allows the initialization process to contain asynchronous steps. A good example of this is loading an external template using AJAX. Initializing UI elements and components will only start when the template has finished loading and has been added to the DOM. The onInitialized callback will be called once all steps in the initialization queue have been completed. A typical initialization process contains the following steps that are executed in order:
- load template (asynchronous or from cache) and insert into the DOM
- initialize UI elements
- initialize components
- initialize regions
When a view is removed/closed the onClose callback is called. This is where you can add code to manually removes references or perform other cleanup actions. Things that always need a manual cleanup:
- Eventlisteners that are not bound via Backbone's native event binding (listenTo).
- Canvasses, Contexts
- Modules (Especially when DOM elements are used inside the module).
- Killing of Tweens (transitions)
- Video players, sliders etc.
View functionality overview
| Functionality | Component | View | LayoutView | | :-------------- | :------------- | :------------- | :------------- | | Events | X | X | X | | UI hash | X | X | X | | Components hash | | X | X | | Regions | | | X |
Available callbacks and events in views
| Callback name | Event name | When | | :----------------------- | :----------------------- | :--------------------------------------------------------------------------------- | | onInitialized | initialized | After the initialization queue is completed. | | onUiInitialized | ui:initialized | After the UI hash has been converted into DOM element references. | | onComponentsInitialized | components:initialized | After the components hash has been converted into components. | | onRegionsInitialized | regions:initialized | After the regions hash has been converted into regions. | | onBeforeTemplateRendered | before:template:rendered | Just before the view's template content has been added to the view's root element. | | onTemplateRendered | template:rendered | The template content has been added to the view's root element. | | onViewAdded | view:added | The view has been added to the DOM by a Region. | | onClose | close | Before a view's remove method will be called. Add your teardown logic here. | | onBeforeRemove | before:remove | Just before the view's root element is removed from the DOM. | | onRemove | remove | The view's root element has been removed from the DOM |
Templates and template caching
With SuperheroJS, templates can be added to a view using the 'template' property. Views will look for a template in the template cache first and if a template is not found it will try to load the template using XHR. After loading a template it is automatically stored in the template cache for further use. Populating the template cache with the most common templates on application startup can be done by rendering the templates into the main HTML page and wrapping them in script tags like this:
<script type="text/template" id="template-name">
<h1>Template</h1>
</script>
SuperheroJS will search for script tags with this format when the application starts and add the contents to the templatecache, using the id as the template identifier.
You can set a basepath for the TemplateCache that it will use to look for templates that are loaded asynchronously.
Superhero.TemplateCache.setBasePath('/templates');
Best practices
Routing
A very robust and powerful pattern to implement view changes within your application is by using the router in conjunction with the RegionManager. By using the url to store the application state and using the RegionManager to render the appropriate views you can quickly set up a very well functioning application. The RegionManager will take care of adding and removing view from the DOM and trigger transitions between views when needed.
routes: {
'' : 'home',
'about' : 'about',
},
home: function() {
Superhero.RegionManager.get('main').show(HomeView);
},
about: function() {
Superhero.RegionManager.get('main').show(AboutView);
}
Order of properties and methods
- constants
- public properties
- private properties
- event/ui/component hashes
- initialize/onInitialized
- setup/remove eventlisteners
- public methods
- private methods
- eventhandlers
Additionally
Use the listenTo method (available in views, modules, models, collections and routers) to add event listeners. Listeners created with this method will automatically be removed when an object is removed from memory.