jComponent / 07. Controllers
Updated: 11. February 2018
Author: Peter Širka

07. Controllers

Professional Support Chat with contributors

Controllers are very helpful for SPA. Controllers can be removed and created dynamically. So removed controller removes all nested jComponents + releases the memory and after some time can be loaded again.

<div data-jc-controller="Users">


    <div data-jc="textbox" data-jc-path="users.name">Name</div>
    <!-- This component will know which is its controller -->


<div data-jc="textbox" data-jc-path="users.age" data-jc-controller="Users"></div>
<!-- This component outside of controller scope will belong to "Users" controller -->

    CONTROLLER('Users', function(ctrl) {

        ctrl.scope = 'users';
        // Scope defines a path scope for the controller
        // It's binded automatically if data-jc-scope="" is defined within data-jc-controller=""

        ctrl.set('name', 'Peter');
        // In the background --> ctrl.scope + '.name' = 'Peter';


Good to know:

  • controllers can be initialized without data-jc-controller attribute
  • data-jc-controller can be binded with data-jc-scope attribute
  • data-jc-controller can be binded with data-jc-config attribute
  • nested components inherit a name of controller automatically
  • controllers have own events

Controller API

Each controller needs to be declared manually via CONTROLLER() method which is global variable.

CONTROLLER(name, callback);
// @name {String} A name of controller
// @callback(ctrl, ctrl_scope, ctrl_element) {Function} A controller scope


// {Object} Configuration

// {jQuery} container (jQuery element)
// It contains element of controller, but it may not exist.

// {String} name of controller

// {String} Path scope
// It contains a path scope. This path is used for writing/reading values.
// With controllers you don't need to use absolute path. The value of this
// property can be changed manually or can be loaded automatically
// if the `data-jc-scope` attribute is defined.


ctrl.aclass(string, [timeout]);
// Adds CSS classes

// Alias for "ctrl.element.append()"

ctrl.attr(name, [value]);
// Alias for "jQuery.attr()"

ctrl.attrd(name, [value]);
// Alias for "jQuery.attr('data-{name}')"

ctrl.change([path], [isChange]);
// +v12.0.4 Can perform a change

// Toggles classes e.g. "+block -hidden"

// +v11.5.0 returns all nested components

ctrl.css(name, [value]);
// Alias for "jQuery.css()"

// Resets to default values

ctrl.emit(name, [a], [b], [c], ..);
// Emits event defined in controller

// Alias for "jQuery.empty()"

ctrl.event(name, [selector], callback);
// Alias for "ctrl.element.on()"

ctrl.exec(name, [a], [b], [c]);
// Executes methods in all components

ctrl.extend(path, value);
// Extends an object according to the current scope

// Alias for "ctrl.element.find(selector)"

// Gets a value according to the current scope

// Alias for hasClass

// Alias for "ctrl.element.html()"

ctrl.inc(path, value);
// Increases a value according to the current scope

// Notifies current scope

ctrl.on(name, fn);
// Captures event

// Generates path according to the current scope

ctrl.push(path, value);
// Pushs a new value according to the current scope

ctrl.rclass(string, [timeout]);
// Removes CSS classes

// Removes all CSS classes which contain `string` or `regexp`

ctrl.reconfigure(value, [callback(key, value)]);
// Parses configuration
// "value" can be "max:10;size:20;required:false" or can be Object

// returns {Boolean}
// +v14.1.1 determines released state, but the one of the parent elements
// needs to be component with releasing mode.

// Removes itself

ctrl.rewrite(path, value);
// Rewrites a value with except notifications

ctrl.set(path, value);
// Sets a value according to the current scope

ctrl.tclass(string, [visible]);
// Toggles classes

ctrl.toggle(cls, visible, [timeout]);
// Alias for "jQuery.toggleClass()"

ctrl.unwatch('path', [fn]);
// +v11.5.0 Unbinds watching

ctrl.update(path, [reset]);
// Updates current scope

ctrl.watch('path', fn(path, value, type), init);
// +v11.5.0 Enables watching of property within controller's scope


ctrl.configure = function(key, value, init, prev) {
    // A configuration delegate

API for controllers

It's defined in CONTROLLERS variable which is a global variable defined in window scope.

Property CONTROLLERS.items

It contains all registered controllers and it's internal and readonly property.

// returns {Object}

Method CONTROLLERS.emit()

This method emits an event within all initialized controllers.

CONTROLLERS.emit(name, [a], [b], [n]);
// @name {String} Event name
// @a {Object} Optional, additional argument
// @b {Object} Optional, additional argument
// @..n {Object} Optional, additional argument
// returns {CONTROLLERS}

Method CONTROLLERS.remove()

This method removes existing controller and its all dependencies.

// @name {String} Name of controller
// returns {CONTROLLERS}

Extending controllers by adding dynamic parts

This is very special feature for apps which are load some parts dynamically and within a controller.

  • SCOPE() is a global variable
  • if the controller doesn't exist SCOPE() waits for it


SCOPE(controller_name, callback);
// @controller_name {String} A name of controller
// @callback(ctrl, ctrl_scope, ctrl_element) {Function} A controller scope


<div>An additional resource</div>

    SCOPE('Users', function(ctrl) {

        // ctrl === "Users" controller
        // this === "USers" controller

        // Here we can extend "Users" controller by adding new methods or properties
        // If the controller is not initialized then this method will wait for the controller