# 05. __Component__

[![+Professional Support](https://www.totaljs.com/img/badge-support.svg)](https://www.totaljs.com/support/) [![+Chat with contributors](https://www.totaljs.com/img/badge-chat.svg)](https://messenger.totaljs.com)

This page describes the whole implementation of reusable component. [__Learn__ from existing components](https://componentator.com).

__Quick navigation:__

- [Definition](#)
- [Properties](#)
- [Delegates](#)
- [Methods](#)
- [Usage in HTML](#)
- [Configuration](#)
- [Data binding](#)

![Component workbench](/download/B20190425T000000015.png)

## Definition

The code below describes a simple component definition with default configuration:

```javascript
COMPONENT('datetime', 'interval:1000;format:dd.MM.yyyy', function(self, config, cls) {

	// This is the component scope
	// self == this
	// config == this.config
	// cls {String} auto-generated class name in the form: "ui-COMPONENTNAME" (+v17)

	var interval;
	
	self.readonly();
	self.blind();

	self.configure = function(name, value, init) {
		switch (name) {
			case 'interval':
				interval && clearInterval(interval);
				interval = setInterval(self.tick, value);
				break;
			case 'format':
				!init && self.tick();
				break;
		}
	};
	
	self.tick = function() {
		self.html(new Date().format(config.format));
	};
	
});
```

__`+v14.0.0` Declaration with a specific version__:

```javascript
// v1
COMPONENT('datetime@1', 'interval:1500;format:dd.MM.yyyy', function(self, config) {
	// ...
});

// v2
COMPONENT('datetime@2', 'interval:500;format:dd.MM.yyyy', function(self, config) {
	// ...
});
```

__`+v14.0.0` Declaration with multiple versions__:

```javascript
// v1
COMPONENT('datetime, datetime@1, datetime@2', 'interval:1000;format:dd.MM.yyyy', function(self, config) {
	// ...
});
```

- [`COMPONENT()`](@17092620450002mpt0#method-component-) is a global variable

## Properties

- [`self._id`](#property-self-_id-)
- [`self.caller`](#property-self-caller-)
- [`self.config`](#property-self-config-)
- [`self.element`](#property-self-element-)
- [`self.global`](#property-self-global-)
- [`self.id`](#property-self-id-)
- [`self.name`](#property-self-name-)
- [`self.path`](#property-self-path-)
- [`self.pathscope`](#property-self-pathscope-)
- [`self.removed`](#property-self-removded-)
- [`self.scope`](#property-self-scope-)
- [`self.siblings`](#property-self-siblings-)
- [`self.template`](#property-self-template-)
- [`self.trim`](#property-self-trim-)
- [`self.type`](#property-self-type-)

### Property: `self._id`

The property contains an internal identificator for this component.

- `readonly`
- returns `String`

### Property: `self.caller`

The property contains a reference to caller/parent of some method executed via `.exec()`

- `readonly`
- returns `Component`
- default `undefined`

### Property: `self.config`

The property contains the whole configuration.

- `readonly`
- returns `Object`

### Property: `self.element`

- `readonly`
- returns `jQuery Element`

### Property: `self.global`

The property contains shared temporary object for all instances of this component.

- returns `Object`

### Property: `self.id`

The property contains an identifactor for this component. jComponent binds `data-jc-id="ID"` attribute to this property automatically. Otherwise `self.id` is same as `self._id`.

- `readonly`
- returns `String`

### Property: `self.name`

The property contains a name of this component.

- `readonly`
- returns `String`

### Property: `self.path`

The property contains the absolute path for data-binding. This value can be changed via [`self.setPath()`](#method-setpath-).

- `readonly`
- returns `String`

### Property: `self.pathscope`

The property contains a path from parent e.g`<div data-jc-scope=""` element (if exists).

- `readonly`
- returns `String`

### Property: `self.removed`

The property indicates whether the component has been removed.

- `readonly`
- returns `Boolean`

### Property: `self.scope`

The property returns a scope data object. Read more in [Scopes section](@17092620430004mpt0).

- `readonly`
- returns `Object`

### Property: `self.siblings`

The property indicates whether the element contains multiple declaration of components in the one element, e.g. `<div data-jc="binder,exec">`

- `readonly`
- returns `Boolean`

### Property: `self.template`

The property can contain `url` address to a template or jQuery `selector` which it starts with `.`, `#` or `[`. Template will be stored in this property before is executed `self.make()`. Default value is binded according to `data-jc-template="DEFAULT_VALUE"` attribute.

__Examples__:
- URL address: `self.template = '/templates/products.html'`
- selector: `self.template = '#mytemplate'`
- or `<div data-jc="YOUR_COMPONENT" data-jc-template="/templates/products.html">`

### Property: `self.trim`

The property can disable auto `trim` string values. It works only with inputs with `data-jc-bind=""` attribute.

- returns `Boolean`
- default `true`

### Property: `self.type`

The property contains a value from `data-jc-type=""` attribute. This `type` describes a data-type for parser or formatter.

- returns `String`


## Delegates

Delegates are executed on some jComponent actions. Some delegates have to return a value.

- [`self.configure(key, value, init, prev)`](#delegate-self-configure-)
- [`self.destroy()`](#delegate-self--)
- [`self.getter(value)`](#delegate-self-getter-)
- [`self.getter2(value)`](#delegate-self-getter2-)
- [`self.init()`](#delegate-self-init-)
- [`self.knockknock(counter)`](#delegate-self-knockknock-)
- [`self.make([template])`](#delegate-self-make-)
- [`self.prerender([template])`](#delegate-self-prerender-)
- [`self.released(is)`](#delegate-self-released-)
- [`self.setter(value, path, type)`](#delegate-self-setter-)
- [`self.setter2(value, path, type)`](#delegate-self-setter2-)
- [`self.state(type, what)`](#delegate-self-state-)
- [`self.validate(value, isInitialValue)`](#delegate-self-validate-)

### Delegate `self.configure()`

`optional` The delegate handles a configuration of the component. It's executed after is component initialized and after `self.make()`, or if [`self.reconfigure()`](#method-reconfigure-) is executed manually. Each `key` is processed independently.

```javascript
self.configure = function(key, value, init, prev) {

	// @key {String}
	// @value {String/Number/Boolean/Object}
	// @init {Boolean} Is initialization?
	// @prev {String/Number/Boolean/Object} A previous value

	switch (key) {
		case 'required':
			self.tclass('required', value);
			break;
		case 'icon':
			self.find('.fa').rclass2('fa-').aclass('fa fa-' + value);
			break;
	}
};
```

### Delegate `self.destroy()`

`optional` The delegate is executed when the component is removing.

```javascript
self.destroy = function() {
	// Clean up
};
```

### Delegate `self.getter()`

`optional` + `internal` The delegate has an internal implementation and it receives a value from HTML controls like `input`, `select` and `textarea` automatically. It's binded with `data-jc-bind` attribute on the target control. Its implementation is a bit complicated.

```javascript
self.getter = function(value) {
	// @value {String} A value from HTML control
};
```

### Delegate `self.getter2()`

`optional` This delegate has a similar functionality as `self.getter()` but you can use it for your own needs without changing `self.getter()`.

```javascript
self.getter2 = function(value) {
	// @value {Object} A processed value
};
```

### Delegate `self.init()`

`optional` This delegate is executed the only onetime for all same components and jComponent evaluates it if the component is used. If you want to share some data between all instances then you can use [`self.global`](#property-self-global-) property.

```javascript
self.init = function() {
	// It's executed the only one time for all instances of same components
};
```

### Delegate `self.knockknock()`

`optional` This delegate is executed each 60 seconds by jComponent automatically.

```javascript
self.knockknock = function(counter) {
	// @counter {Number}
};
```

### Delegate `self.make()`

`optional` This delegate is executed when the component is creating. If you fill [`self.template`](#property-self-template-) property then the `template` argument will contain obtained data.

```javascript
self.make = function(template) {
	// @template {String} Optional, it contains processed template data
};
```

### Delegate `self.prerender()`

`optional` This delegate can update processed `template` before is executed `self.make()`. It works with filled [`self.template`](#property-self-template-) property only.

```javascript
self.prerender = function(template) {
	// @template {String}
	// IMPORTANT: it needs to return a modified value
	return template.replace(/\n/g, '<br />');
};
```

### Delegate `self.released()`

`optional` This delegate is executed when the component parent component performs `release` method. For example: `j-Form` component - when the form is closed the component executes `released(true)` for all nested components and when the form is going to visible the component executes `released(false)` for all nested components.

```javascript
self.released = function(is) {

	// @is {Boolean} true = the component is released by parent component, false = isn't released

	if (is) {
		// here you can clean-up DOM because e.g. component is hidden
	} else {
		// here you can restore previous state because control is visible
	}
	
};
```

### Delegate `self.setter()`

`optional` The delegate observes changes in the model according to the defined `path`. It's executed everytime when data changes. Default implementation contains auto-mechanism for HTML inputs like `<input data-jc-bind />`, `<textarea data-jc-bind>` and `<select data-jc-bind>`.

```javascript
// Custom implementation:
self.setter = function(value, path, type) {

	// @value {Object}
	// @path {String}
	// @type {Number} 0: init, 1: manually, 2: by input, 3: default 

	// Apply formatters
	value = self.formatter(value);

	// Render the value:
	self.html(value == null ? 'NULL' : value.toString());
};
```

### Delegate `self.setter2()`

`optional` This delegate has a similar functionality as `self.setter()` but you can use it for your own needs without changing `self.setter()`.

```javascript
self.setter2 = function(value, path, type) {

	// @value {Object}
	// @path {String}
	// @type {Number} 0: init, 1: manually, 2: by input, 3: default 
	
};
```

### Delegate `self.state()`

`optional` This delegate can change CSS when the value is invalid or something else.

```javascript
self.state = function(type, what) {

	// type === 0 : init
	// type === 1 : manually
	// type === 2 : by input
	// type === 3 : by default

	// what  === 1 : valid
	// what  === 2 : dirty
	// what  === 3 : reset
	// what  === 4 : update
	// what  === 5 : set
	// what  === 6 : notify

	self.tclass('error', type === 0 ? false : self.isInvalid());
};
```

### Delegate `self.validate()`

`optional` This delegate validates a value. It's executed by jComponent automatically when the value is modified. This delegate has to return a `Boolean` value.

```javascript
self.validate = function(value, isInitialValue) {

	if (isInitialValue)
		return true;

	return value.length > 0;
};
```

## Methods

- [`self.aclass(cls, [delay])`](#method-self-aclass-)
- [`self.append(value)`](#method-self--)
- [`self.attr(name, [value])`](#method-self-attr-)
- [`self.attrd(name, [value])`](#method-self-attrd-)
- [`self.bindchanges()`](#method-self-bindchanges-)
- [`self.bindexact()`](#method-self-bindexact-)
- [`self.bindvisible([delay])`](#method-self-bindvisible-)
- [`self.blind()`](#method-self-blind-)
- [`self.data(path, [value])`](#method-self-data-)
- [`self.caniuse(string)`](#method-self-caniuse-)
- [`self.change([is])`](#method-self-change-)
- [`self.classes(string)`](#method-self-classes-)
- [`self.closest(selector)`](#method-self-closest-)
- [`self.command(name, fn)`](#method-self-command-)
- [`self.compile([container])`](#method-self-compile-)
- [`self.css(name, [value])`](#method-self-css-)
- [`self.datasource(path, callback, [init])`](#method-self-datasource-)
- [`self.default([reset])`](#method-self-default-)
- [`self.emit(event_name, [a], [b], [..n])`](#method-self-emit-)
- [`self.empty()`](#method-self-empty-)
- [`self.evaluate([value], expression, [is_value])`](#method-self-evaluate-)
- [`self.event(eventname, [selector], callback)`](#method-self-event-)
- [`self.exec(name, [a], [b], [..n])`](#method-self-exec-)
- [`self.extend(value, [type])`](#method-self-extend-)
- [`self.find(selectors)`](#method-self-find-)
- [`self.formatter(value_or_fn)`](#method-self-formatter-)
- [`self.get([path])`](#method-self-get-)
- [`self.hclass(cls)`](#method-self-hclass-)
- [`self.html([value])`](#method-self-html-)
- [`self.import(url, [callback], [insert], [preparator])`](#method-self-import-)
- [`self.inc(value, [type])`](#method-self-inc-)
- [`self.invalid()`](#method-self-invalid-)
- [`self.isInvalid()`](#method-self-isinvalid-)
- [`self.main()`](#method-self-main-)
- [`self.nested()`](#method-self-nested-)
- [`self.nocompile()`](#method-self-nocompile-)
- [`self.nodirty()`](#method-self-nodirty-)
- [`self.noscope()`](#method-self-noscope-)
- [`self.notify()`](#method-self-notify-)
- [`self.novalidate()`](#method-self-novalidate-)
- [`self.parent([selector])`](#method-self-parent-)
- [`self.parser(value_or_fn)`](#method-self-parser-)
- [`self.push(value)`](#method-self-push-)
- [`self.rclass(cls, [delay])`](#method-self-rclass-)
- [`self.rclass2(search)`](#method-self-rclass2-)
- [`self.readonly()`](#method-self-readonly-)
- [`self.reconfigure(value, [callback])`](#method-self-reconfigure-)
- [`self.refresh([updatePath])`](#method-self-refresh-)
- [`self.release(is)`](#method-self-release-)
- [`self.releasemode(type)`](#method-self-releasemode-)
- [`self.remove()`](#method-self-remove-)
- [`self.replace(el, [remove])`](#method-self-replace-)
- [`self.reset()`](#method-self-reset-)
- [`self.rewrite(value)`](#method-self-rewrite-)
- [`self.scopepath(path)`](#method-scopepath-)
- [`self.set(value, [type])`](#method-self-set-)
- [`self.setPath(path)`](#method-self-setpath-)
- [`self.singleton()`](#method-self-singleton-)
- [`self.skip([path])`](#method-self-skip-)
- [`self.tclass(cls, [visible])`](#method-self-tclass-)
- [`self.text([value])`](#method-self-text-)
- [`self.unwatch(path, [handler])`](#method-self-unwatch-)
- [`self.validate2()`](#method-self-validate2-)
- [`self.watch([path], handler, [init])`](#method-self-watch-)

### Method: `self.aclass()`

This method is alias for `self.element.addClass()` and it adds CSS `class` into the element classes.

```javascript
self.aclass(cls, [delay]);
// @cls {String}
// @delay {Number} Optional, in milliseconds
// returns {Component}
```

### Method: `self.append()`

This method is alias for `self.element.append()` and it appends a new content into the element. A value can be `HTML`.

```javascript
self.append(value);
// @value {String} or {Array String}
// returns {Component}
```

### Method: `self.attr()`

This method is alias for `self.element.attr(name, [value])` and it can get/set a value into the element attribute.

```javascript
self.attr(name, [value]);
// @name {String}
// @value {String} Optional
// returns {Component}
```

### Method: `self.attrd()`

This method is alias for `self.element.attr(name, [value])` and it can get/set a value into the element attribute with `data-` prefix for name of attribute.

```javascript
self.attrd(name, [value]);
// @name {String}
// @value {String} Optional
// returns {Component}

self.attrd('name', 'value');
// sets a value to the "data-name" attribute
```

### Method: `self.bindchanges()`

`+v14.2.0` This method binds changes only. If `setter` will get the same value as a previous value then skips binding.

```javascript
self.bindchanges();
// returns {Component}
```

### Method: `self.bindexact()`

`+v14.1.2` This method sets binding of values when the the modification `path` is same as the component path or the `path` is part of parent `path`. 

```javascript
self.bindexact();
// returns {Component}
```

### Method: `self.bindvisible()`

`+v13.0.0` This method sets binding of values only when the component is not `released`, it depends on releasing of the parent component.

```javascript
self.bindvisible([delay]);
// @delay {Number} A delay for binding value, default: DEF.delaybinder (200)
// returns {Component}
```

### Method: `self.blind()`

This method sets the component as blind. Component will be skipped when jComponent performs data-binding. If your component won't work with data-binding then this option can increase a performance of your web app.

```javascript
self.blind();
// returns {Component}
```

### Method: `self.data()`

`+v15` This method can set or get data from internal component repository. Data can be used for `data-bind=""` attribute and nested j-Components.

```javascript
self.data(path, [value]);
// returns {Object}

// Sets:
self.data('some.path', 'Test');
// It depends all:
// <element data-bind="@some.path"
// <element data-jc="somecomponent__@some.path"

// Gets:
self.data('some.path');
```

### Method: `self.canisue()`

`+v17` This method checks a component whether exists or no.

```javascript
self.caniuse(name);
// @name {String} A component name
// returns {Number}

// 0: component doesn't exist
// 1: component is initialized
// 2: component is not initialized but it's declared (lazy load)

console.log(self.caniuse('calendar'));
// Output: 1

console.log(self.caniuse('datepicker'));
// Output: 2

console.log(self.caniuse('newcomponent'));
// Output: undefined
```

### Method: `self.change()`

This method can perform a change state. It changes `dirty` state and contacts all components which listen on `path`.

```javascript
self.change([is]);
// @is {Boolean} Optional
// returns {Component}

// Is a change?
console.log(self.change());
// Output: false

// Perform a change
self.change(true);

console.log(self.change());
// Output: true
```

### Method: `self.classes()`

__`REMOVED IN v18`__ This method can add or remove CSS classes.

```javascript
self.classes(value);
// @value {String}
// returns {Component}

self.classes('+selected +hover -disabled -fa-home +fa-check-circle');
// +class -> is for adding
// -class -> is for removing
```

### Method: `self.closest()`

This method is alias for `self.element.closest(selector)`, it searchs `selector` in all parent elements.

```javascript
self.closest(selector);
// @selector {String}
// returns {jQuery}
```

### Method: `self.command()`

`+v17` This method registers a new component command.

```javascript
self.command(name, fn);
// @name {String}
// @fn {Function} a processor


self.command('refresh', function() {
	// DO SOMETHING
});

// EXECUTION
CMD('refresh');
```

### Method: `self.compile()`

This method compiles new and uncompiled jComponents.

```javascript
self.compile([container]);
// @container {jQuery Element} Optional, default: current element
// returns {jQuery}
```

### Method: `self.css()`

This method is alias for `self.element.css(name, [value])`, it can set CSS or get.

```javascript
self.css(name, [value]);
// @name {String}
// @value {String} Optional
// returns {Component} or {String}

// Writing:
self.css('margin', '5px');
self.css('width', '100%');

// Reading:
console.log(self.css('height'));
```

### Method: `self.datasource()`

This method can watch some additional data-source. __Each next declaration of `self.datasource()` cancels previous declaration.__

```javascript
self.datasource(path, callback, [init]);
// @name {String}
// @callback {Function(path, value, type)}
// @init {Boolean} Optional, invokes the callback with a value (default: true)
// returns {Component}
// +v12.0.0

self.datasource('products.manufacturers', function(path, value, type) {
	// @path {String}
	// @value {Object}
	// @type {Number} 0: init, 1: manually, 2: by input, 3: default 
});
```

### Method: `self.default()`

This method can set a default value for the current component path.

```javascript
self.default([reset]);
// @reset {Boolean} Optional, it resets "dirty" and "valid" states (default: true)
// returns {Component}
```

### Method: `self.emit()`

This method emits an event within jComponent. Is alias for [`EMIT()`](@17092620450002mpt0#method-emit-) method.

```javascript
self.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 {Component}
```

### Method: `self.empty()`

This method is alias for `self.element.empty()`, it removes the whole content of element and __important__ removes all components which the parent component is this component.

```javascript
self.empty();
// returns {Component}
```

### Method: `self.evaluate()`

This method is alias for `self.element.empty()`, it removes the whole content of element.

```javascript
self.evaluate([value], expression, [is_value]);
// @value {Object} Optional, can be object if "is_value" is "true"
// @expression {String} A condition.
// @is_value {Boolean} Optional, default: false
// returns {Boolean}

// With reading a value according to the component "data-jc-path"
var isTeenager = self.evaluate('value >= 10 && value <= 20');

// With a real value
var isTeenager = self.evaluate(15, 'value >= 10 && value <= 20', true);
```

### Method: `self.event()`

This method registers a new event for the element. Is alias for `self.element.on()` method.

```javascript
self.event(name, [selector], callback);
// @name {String} Event name
// @selector {String} Optional, custom selector
// @callback {Function}
// returns {Component}

self.event('keydown', 'input', function(e) {
	console.log(e.which);
});
```

### Method: `self.exec()`

The method executes a method according to the path in all nested components. It wont't throw any exception if the method not exist.

```javascript
self.exec(name, [a], [b], [..n]);
// @name {String} A method name
// @a {Object} Optional, additional argument
// @b {Object} Optional, additional argument
// @..n {Object} Optional, additional argumentň
// returns {Component}

self.exec('refresh');
// Executes in all nested components --> component.refresh();
```

### Method: `self.extend()`

The method extends a current value by adding/rewrite new fields with new values.

```javascript
self.extend(value);
// @value {Object}
// returns {Component}

self.extend({ age: 35, alias: 'Peter' });
```

### Method: `self.find()`

This method finds elements according to the `selector`. Is alias for `self.element.find()` method.

```javascript
self.find(selector);
// @selector {String}
// returns {jQuery}

self.find('input').prop('disabled', true);
```

### Method: `self.formatter()`

This method can register a new formatter for this component or can format a value. The method uses all registered global formatters [`MAIN.formatter()`](@17092508010002yge0#method-main-formatter-) too for formatting values.

```javascript
// For registering formatter:
self.formatter(fn);
// @fn {Function(path, value, type} Function needs to return a value
// returns {Component}

self.formatter(function(path, value, type) {
	// @path {String}
	// @value {Object}
	// @type {String} According to the "data-jc-type" attribute or "self.type"
	return typeof(value) === 'string' ? value.toUpperCase() : value;
});

// You can register more fomatters in a row
self.formatter(function(path, value, type) {
	return typeof(value) === 'string' ? value.split('').reverse().join('') : value;
});

// For formatting:
self.formatter(value);
// @value {Object}
// returns {Object}

console.log(self.formatter('Peter'));
// Output: RETEP
```

### Method: `self.get()`

This method can get a value according to the `data-jc-path` or `path`.

```javascript
self.get([path]);
// @path {String} Optional, default current component path
// returns {Object}

console.log(self.get());
// Gets a value: "window[component.path]"

console.log(self.get('users.grid.items'));
// Gets a value: "window.users.grid.items"
```

### Method: `self.hclass()`

This method is alias for `self.element.hasClass()`, it determines `class` in the element.

```javascript
self.hclass(cls);
// @cls {String}
// returns {Boolean}
```

### Method: `self.html()`

This method is alias for `self.element.html()`, it can set/get a content of the element.

```javascript
self.html(value);
// @value {String} or {String Array}
// returns {String} or {jQuery Element}
```

### Method: `self.import()`

__`REMOVED IN v18`__ This method can import some content from external source to this element. __IMPORTANT__: Instead of this function use `IMPORT()`.

```javascript
self.import(url, [callback], [insert], [preparator]);
// @url {String}
// @callback {Function} Optional
// @insert {Boolean} Optional, default: true
// @preparator {Function(content)} Optional, it needs to return modified content
// returns {Component}

self.import('/templates/products.html');
```

### Method: `self.inc()`

The method increments a `Number` according to the `component.path`.

```javascript
self.inc(value);
// @value {Number}
// returns {Component}

self.inc(5);
```

### Method: `self.invalid()`

The method sets the state of this component to invalid and it contacts all components listen on the `path`.

```javascript
self.invalid();
// returns {Component}
```

### Method: `self.isInvalid()`

The method checks a state whether the component is invalid or valid.

```javascript
self.isInvalid();
// returns {Boolean}
```

### Method: `self.main()`

The method returns a parent component instance if exists (otherwise: `null`).

```javascript
self.main();
// returns {Component}
```

### Method: `self.nested()`

__`REMOVED IN v18`__. The method returns all nested components.

```javascript
self.nested();
// returns {Array Component}
```

### Method: `self.nocompile()`

`+v16` The method disables jComponent `compilation` for nested elements. This feature can increase the performance in several cases.

```javascript
self.nocompile();
// returns {Component}
```

### Method: `self.nodirty()`

The method disables `dirty` state.

```javascript
self.nodirty();
// returns {Component}
```

### Method: `self.noscope()`

The method disables scopes according to the `data-jc-scope` attribute.

```javascript
self.noscope();
// returns {Component}
```

### Method: `self.notify()`

The method notifies a `setter` in all components according to the `component.path`.

```javascript
self.notify();
// returns {Component}
```

### Method: `self.novalidate()`

The method disables validation.

```javascript
self.novalidate();
// returns {Component}
```

### Method: `self.parent()`

The method is alias for `self.element.parent()`, it gets a parent element.

```javascript
self.parent([selector]);
// @selector {String} Optional, a jQuery selector
// returns {jQuery}
```

### Method: `self.parser()`

This method can register a new parser for this component or can parse a value. The method uses all registered global parsers [`MAIN.parser()`](@17092508010002yge0#method-main-formatter-) too for parsing values.

```javascript
// For registering parser:
self.parser(fn);
// @fn {Function(path, value, type} Function needs to return a value
// returns {Component}

self.parser(function(path, value, type) {
	return typeof(value) === 'string' ? value.parseDate() : value;
});

// For parsing:
self.parser(value);
// @value {Object}
// returns {Object}

console.log(self.parser('2017-11-06'));
// Output: Mon Nov 06 2017 00:00:00 GMT+0100 (CET)
```

### Method: `self.push()`

The method pushs a new item into the `Array` according to the `component.path`.

```javascript
self.push([path], value);
// @value {Object}
// returns {Component}

self.push('Node.js');
self.push(['Node.js', 'Total.js']);
```

### Method: `self.rclass()`

The method is alias for `self.element.removeClass()`, it removes a `class` from the current element.

```javascript
self.rclass(cls, [delay]);
// @cls {String} Class names
// @delay {Number} Optional, default: 0
// returns {jQuery}
```

### Method: `self.rclass2()`

The method removes classes according to the text to search.

```javascript
self.rclass2(search);
// @search {String} or {RegExp}
// returns {Component}

self.rclass2('fa-');
```

### Method: `self.readonly()`

The method enables readonly mode for the component. It disables `dirty` and `valid` states, `getter`, `setter`, parsers and formatters. This option can improve performance.

```javascript
self.readonly();
// returns {Component}
```

### Method: `self.reconfigure()`

The method reconfigures the component. Internally it executes `self.configure` delegate. [Read more about configuration](#configuration).

```javascript
self.reconfigure(value);
// @value {String} or {Object}
// returns {Object}

self.reconfigure('maxlength:50;required:false');

// is same as:

self.reconfigure({ maxlength: 50, required: false });
```

### Method: `self.refresh()`

The method executes the `component.setter` with a refreshed value according to the `component.path`.

```javascript
self.refresh([updatePath]);
// @updatePath {Boolean} Optional, "true" notifies all components on the path (default: false)
// returns {Component}
```

### Method: `self.release()`

The method performs `release` state for all nested components.

```javascript
self.release(is);
// @is {Boolean} "true": release state, "false" restore state
// returns {Component}

// E.g. component is hidden:
self.release(true);

// E.g. component will be visible:
self.release(false);
```

### Method: `self.releasemode()`

The method performs `release` state for all nested components.

```javascript
self.releasemode(type);
// @type {String/Number/Boolean}
// returns {Component}

// "auto" or 0 means (DEFAULT):
// The component releasing dependes on the parent component.

// "true" or true or 1 means:
// The component accepts only released state from the parent component and it applies it to the nested components. So this component can change another state for nested components.

// "false" or false or 2 means:
// The component accepts only not released state from the parent component and it applies to the nested components. So this component can change another state for nested components.

// "manual" or 3 means:
// The component controls nested components manually (so it doesn't matter on the release state of the parent component)
```

### Method: `self.remove()`

The method removes this component from the DOM and executes `destroy` delegate.

```javascript
self.remove();
// returns {Component}
```

### Method: `self.replace()`

The method replaces the current element for a new.

```javascript
self.replace(el, [remove]);
// @el {jQuery} a new element
// @remove {Boolean} Optional, removes older element (default: false)
// returns {Component}
```

### Method: `self.reset()`

The method resets `dirty` and `valid` state.

```javascript
self.reset();
// returns {Component}
```

### Method: `self.rewrite()`

The method rewrites a value according to the `component.path` and it won't notify all listeners.

```javascript
self.rewrite(value);
// @value {Object}
// returns {Component}
```

### Method: `self.scopepath()`

`+v17` The method returns an updated path according to the scope --> if the path will contain `?` char which will be replaced.

```javascript
self.scopepath(path);
// returns {String}
```

### Method: `self.set()`

The method sets a value according to the `component.path`.

```javascript
self.set(value, [type]);
// @value {Object}
// @type {Number/String} Optional
// returns {Component}
```

### Method: `self.setPath()`

The method rewrites `component.path`.

```javascript
self.setPath(path);
// @path {String} New path
// returns {Component}
```

### Method: `self.singleton()`

The method creates a single instance of the component. So if the component will be declared multiple times then jComponent creates the only one instance and another declarations will be skipped.

```javascript
self.singleton();
// returns {Component}
```

### Method: `self.skip()`

The method skips future calling of `component.setter`. __It's incremental.__

```javascript
self.skip([path]);
// @path {String} Optional, absolute path (default: "data-jc-path")
// returns {Component}

// Skips a next calling of setter
self.skip();

// or with multiple paths:
self.skip('users.form.firstname, users.form.lastname');

// returns {Component}
```

### Method: `self.tclass()`

The method toggles `class`, it's alias for `self.element.toggleClass()`.

```javascript
self.tclass(cls, [add]);
// @cls {String} A class name
// @add {Boolean} Optional, true: adds class, false: remove class, undefined: toggles class
// returns {Component}
```

#### Method: `self.text()`

This method is alias for `self.element.text()`, it can set/get a content of the element.

```javascript
self.text([value]);
// @value {String}
// returns {String} or {jQuery Element}
```

### Method: `self.unwatch()`

The method unregisters a monitoring of value according to the `path` argument.

```javascript
self.unwatch(path, [handler]);
// @path {String}
// @handler {Function} Optional
// returns {Component}
```

### Method: `self.validate2()`

`+v13.0.4` The method performs validation with refreshing `state` of component.

```javascript
self.validate2();
// returns {Boolean}
```

### Method: `self.watch()`

The method registers a monitoring of value according to the `path` argument.

```javascript
self.watch(path, handler, [init]);
// @path {String}
// @handler {Function}
// @init {Boolean} Optional, it evaluates path now (default: false)
// returns {Component}

self.watch('products.items', function(path, value, type) {
	// @path {String}
	// @value {Object}
	// @type {Number} 0: init, 1: manually, 2: by input, 3: default
});
```

## Usage in HTML

Each component needs to be initialized in HTML directly:

__Component declaration__:

```html
<div data---="COMPONENT_NAME"></div>
<span data---="COMPONENT_NAME"></span>
<whatever data---="COMPONENT_NAME"></whatever>

<!-- OR OLDER DECLARATION -->

<div data-jc="COMPONENT_NAME"></div>
<span data-jc="COMPONENT_NAME"></span>
<whatever data-jc="COMPONENT_NAME"></whatever>
```

__Component declaration with data-binding__:

```html
<div data---="COMPONENT_NAME__path.to.model"></div>
```

- jComponent converts a component `path.to.model` to the path in the `window` scope. It converts it to e.g. `window.path.to.model` in the background
- so the component will watch a value on the `path.to.model` path

__Component declaration with data-binding and configuration__:

- separator can be `__` or `___` or `_____` and can contain spaces between values
- developer can choose declaration between __new__ and __older__

```html
<div data-jc="component __ path __ config __ default value"></div>

Examples:

<div data---="textbox___form.name___required:true;maxlength:30">NEW</div>
<div data-jc="textbox" data-jc-path="form.name" data-jc-config="required:true;maxlength:30">OLD</div>

<div data---="textbox___form.name___required:true;maxlength:30___'Peter'">NEW</div>
<div data-jc="textbox" data-jc-path="form.name" data-jc-config="required:true;maxlength:30" data-jc-value="'Peter'">OLD</div>

<div data---="textbox __ form.name __ required:true;maxlength:30 __ 'Peter'">NEW</div>
<div data-jc="textbox" data-jc-path="form.name" data-jc-config="required:true;maxlength:30" data-jc-value="'Peter'">OLD</div>
```

- jComponent follows HTML 5 standards

## Configuration

The configuration of components is a very important part of reusable components. Configuration is stored in `data---="COMPONENT__PATH__key1:value1;key2:value2"` attribute.

__Good to know:__

- `Number` is parsed as `Number`, e.g. `key:123` or `key:123.45`
- `Boolean` is parsed as `Boolean`, e.g. `key:false` or `key:true`
- `Environment` values are parsed automatically, e.g. `key:[key_in_env]`
- if your value contains a `:` colon you can encode it via backslash `\:`
- you don't have to encode absolute URL addresses, e.g. `key:https://www.google.sk` will work without encoding
- __IMPORTANT__: configuration can be binded with `path.to.variable` like this: `data-jc-config="=path.to.variable"`

Each component needs to implement the delegate below:

```javascript
// This delegate is executed for each key from configuration
self.configure = function(key, value, init, prev) {

	// @key {String}
	// @value {String/Number/Boolean/Object}
	// @init {Boolean} Is initialization?
	// @prev {String/Number/Boolean/Object} A previous value

	switch (key) {
		case 'required':
			self.tclass('required', value);
			break;
		case 'icon':
			self.find('.fa').rclass2('fa-').aclass('fa fa-' + value);
			break;
	}
	
};
```

Processed component can be reconfigured via:

- `self.reconfigure('key3:value3;key4:value')` or
- `self.reconfigure({ key3: 'value3', key4: 'value4' })`
- __Quick tip__: `SETTER('#mytextboxid', 'reconfigure', 'required:false')`

Reconfiguration doesn't cancel previous configuration, but it extends it.

#### Special configuration

Special configuration is part of jComponent `+v16`.

- `$id:string` component id
- `$class:string` can toggle class when the component is ready
- `$binding:1` enables real-time binding only
- `$binding:2` enables binding after change only
- `$delay:300` binding delay
- `$init:path.to.method` executes a method if the component is initialized
- `$setter:path.to.method` executes a method if the setter is modified
- `$state:path.to.method` executes a method if the component changes the state
- `$reconfigure:path.to.method` executes a method if the component is reconfigured
- `$compile:false` disables a compilation for nested components
- `$url:/editor.html` downloads the declaration of component __only one time__ before is component processed (`+v17`)

## Data Binding

Data Binding performs two way Data Binding between a component and a model.

- components creates a listener on the `path` and the component will react on its change
- delegate `component.setter` processes data-binding on the component side
- these global methods perform a change in the model and notify all components [`SET()`](@17092620450002mpt0#method-set-), [`PUSH()`](@17092620450002mpt0#method-push-), [`INC()`](@17092620450002mpt0#method-inc-), [`EXTEND()`](@17092620450002mpt0#method-extend-) and [`UPDATE()`](@17092620450002mpt0#method-update-)

```html
<div data---="textbox__myform.name"></div>
<div data---="json__myform"></div>
<div data---="textbox__user.name"></div>

<script>
	SET('myform.name', 'Peter');
	// This method assigns a value "Peter" according to the path "window.myform.name"
	// "window.myform.name" will contain "Peter"
	// Components: textbox + json will be notified because they listen on the modified path
	// Component textbox with "user.name" won't be notified because it's listening on another path

	SET('user', { name: 'Peter' });
	// This method assigns a value {Object} according to the path "window.user"
	// "window.user" will contain the {Object}
	// Only component textbox with "user.name" will contain a modified value
</script>
```

`+v14.2.0` supports inline helpers:

```html
<div data---="textbox__myform.name --> value.toUpperCase()"></div>
```

## Special binding for nested components

`+v16` supports special data-binding for nested jComponents. Path of nested component must start with `@` char.

__For example__:

```html
<div data---="A__path">
	<div data---="B__@path"></div>
</div>
```

- component `A` can set data to `B` component via `component.data('path', 'some data')`
- nested component `B` is listening on the owner/parent component `A`

## Special binding for data-bind

`+v18` supports binding a value via `data-bind` command `set`. This binding of value works with `VBINDARRAY` too, but only in readonly mode.

- `.` dot in the component's path is very important, it allows to bind a value from `data-bind`

__For example__:

```html
<div data-bind="path.to.value__set" data---="textbox__.__required:1"></div>

or 

<div data-bind="path.to.value__set:value.toUpperCase()" data---="textbox__.__required:1"></div>
```