# 06. __Scopes__

[![+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)

__Scopes__ can simplify paths in HTML declaration. In other words: scopes can reduce paths in all nested components.

__Quick navigation:__

- [How does it work?](#)
- [New scopes in `+v17`](#)
- [Isolated scopes with `!` exclamation mark](#)
- [Anonymous scope with `?` question mark](#)
- [Special usage with `?` question mark](#)
- [Skip parent scopes](#)
- [Good to know](#)

## How does it work?

- first you need to implement an element with `data-scope` attribute
- `data-scope` can contain `path` or can be empty

```html
<!-- WITHOUT SCOPE -->
<div>
	<div data---="textbox__users.form.firstname">Name</div>
	<div data---="textbox__users.form.age">Age</div>    
</div>

<!-- WITH SCOPE -->
<div data-scope="users.form">
	<div data---="textbox__?.firstname">Name</div>
	<div data---="textbox__?.age">Age</div>    
</div>
```

## New scopes in `+v17`

__+v17__ improves scopes like `data-bind`. So if you use `data-scope` attribute then you need to use `?` (question mark) in each component where you want to use scope. `?` will be replaced for a scope path. Otherwise will be `path` independent in the component. We recommend to use this declaration.

```html
<div data-scope="users.form">
	<div data---="textbox__?.firstname">Name</div>
	<div data---="textbox__?.age">Age</div>    
</div>
```

#### :warning: New declaration

```html
<div data-scope="PATH__OPTIONS__DEFAULT_VALUE">

</div>

EXAMPLE:

<div data-scope="users.form__init:users_form_init__{}">
	- method "users_form_init" will be evaluated if the scope will be initialized
	- {} will be a default value for "users.form"
</div>
```

__Options__:

- `init:path.to.method` evaluates a method when the scope is initialized
- `class:class_name` toggles class for the element
- `isolated:true` can enable isolated scope (a parent scope path won't be inherited)

## Disallow scopes for selected components

__IMPORTANT__: `<= v16` jComponent supports `data-jc-noscope="true"` attribute which can disallow scope for the component. In `+v17` is this attribute deprecated.

```html
<div data-jc-scope="users.form">

	<div data---="textbox__firstname">Name</div>
	<!-- path will be: users.form.firstname -->

	<div data---="textbox__age">Age</div>    
	<!-- path will be: users.form.age -->

	<!-- DISALLOW SCOPE -->
	<div data---="textbox__users.search" data-jc-noscope="true"></div>
	<!-- path will be: users.search -->
    
</div>
```

## Isolated scopes with `!` exclamation mark

Independent scopes can rewrite current scope. __Independence__ is enabled by adding exclamation mark `!` into the scope path `data-scope="!products.form"` or you can use option like this `data-scope="products.form__isolated:true"`.

```html
<div data-scope="users.form">

	<div data---="textbox__?.name">Name</div>
	<!-- path will be: users.form.name -->
    
	<!-- Isolated scope -->
	<div data-scope="products.form__isolated:true">
		<div data---="textbox__?.name">Name</div>
		<!-- path will be: products.form.name -->
	</div>

	<!-- Inherited scope -->
	<div data-scope="products.form">
		<div data---="textbox__?.name">Name</div>
		<!-- path will be: users.form.products.form.name -->
	</div>
    
</div>
```

## Anonymous scope with `?` question mark

Anonymous scopes are very good option for creating reusable independent web parts, e.g. `Contact form`, `Subscriber form`, etc..

- jComponent generates random path for this scope
- path will have more than 15 chars
- path will be stored in `window` object
- example: `jmhjxgietazasfazfqxqb`

```html
<div data-scope="?">

	<div data---="textbox__?.name">Name</div>
	<!-- path will be: random_path.name -->

</div>

<!-- EXAMPLE -->

<div data-scope="?">

	<div data---="textbox__?.name">Name</div>
	<!-- path will be: aoyhdvlmloorhzomzm.name -->

</div>

<div data-scope="?">

	<div data---="textbox__?.name">Name</div>
	<!-- path will be: xsngbvdllnidnaownly.name -->

</div>
```

### How can I obtain anonymous path?

```html
<div data-scope="?__init:scopeinit">
	...
</div>

<script>
	function scopeinit(path, el) {
	// path {String}
	// el {jQuery Element}

	var scope = el.scope();
	// or
	var scope = this; 

	// scope === Scope object
}
</script>
```

## Scope object

__Properties__:

```javascript
path;
// returns {String}
// A scope path

config;
// +v17
// returns {Object}
// A parsed configuration

elements;
// returns {Array of DOM elements}
// All scopes (parent -> children)

isolated;
// returns {Boolean}
// Determines isolated scope

element;
// returns {jQuery element}
// A scope element
```

__Methods__:

```javascript
scope.FIND();
// alias to global method: FIND() but this method finds components in the scope element only

scope.SETTER();
// alias to global method: SETTER() but this method works for components in the scope element only

scope.reset([path], [delay]);
// @path {String} Optional, it's additional path to scope path
// @delay {Number} Optional
// This method performs RESET() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

scope.default([path], [delay]);
// @path {String} Optional, it's additional path to scope path
// @delay {Number} Optional
// This method performs DEFAULT() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

scope.set(path, value, [delay], [reset]);
// @path {String} It's additional path to scope path
// @value {Object}
// @delay {Number} Optional
// @reset {Boolean} Optional, performs reset
// This method performs SET() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

scope.push(path, value, [delay], [reset]);
// @path {String} It's additional path to scope path
// @value {Object}
// @delay {Number} Optional
// @reset {Boolean} Optional, performs reset
// This method performs PUSH() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

scope.update(path, [delay], [reset]);
// @path {String} It's additional path to scope path
// @delay {Number} Optional
// @reset {Boolean} Optional, performs reset
// This method performs UPDATE() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

scope.get(path);
// @path {String} It's additional path to scope path
// returns {Object}
// This method performs GET() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

scope.can([flags]);
// @flags {Array String} Selector flags
// returns {Boolean}
// This method performs CAN() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

scope.errors([flags], [highlight]);
// @flags {Array String} Selector flags
// @highlight {Boolean} Highlight invalid components
// returns {Array jComponents}
// This method performs ERRORS() for the scope path
// +v18: path can contain "?" which will be replaced with a scope path

// SELECTOR FLAGS:
// @hidden - jComponent finds all hidden components
// @visible - jComponent finds all visible components
// @disabled - jComponent finds all components which have disabled inputs
// @enabled - jComponent finds all components which have enabled inputs
```

## Special usage with `?` question mark

Scopes supports one more thing. If the component path will contain `?` question mark in the path then the scope replaces this `?` mark with the current scope path.

```html
<div data-scope="users">

	<div data---="textbox__address.?.street">Street</div>
	<!-- path will be: address.users.street -->

</div>
```

## Skip parent scopes

`+v17` this behaviour is targeted for special cases. You can skip parent scopes in the form `?COUNT_OF_SKIP`, the example below describes more:

```html
<div data-scope="level1">
	<div data-scope="level2">
		<div data-scope="level3">
			
			<div data-bind="?.name"></div>
			<!-- Path will be decoded as: level1.level2.level3.name -->

			<div data-bind="?1.name"></div>
			<!-- Path will be decoded as: level1.level2.name -->

			<div data-bind="?2.name"></div>
			<!-- Path will be decoded as: level1.name -->

		</div>
	</div>

</div>
```

## Good to know

- __IMPORTANT__: scope must contain some jComponent
- __scopes__ need to be declared in HTML directly
- __scopes__ can have nested scopes
- jComponent contains a list of used scopes in [`component.scope`](@17092508010003yge1#property-self-scope-) property
- scope DOM element contains the whole path stored in `element.$scopedata` property
- obtaining scope with help of jQuery: `$('selector').scope()` returns a scope instance