# Dependency Injection and Nested View

Одной из основных проблем **Backbone.js** являеться создание layout'ов из `view`, например использование `view` внутри другой `view`. Именно по этой причине появилось множество библиотек которые дополняют **Backbone.js** для решения данно проблемы.

Например всем известные [Marionette](http://marionettejs.com/) или [Chaplinjs](http://chaplinjs.org/).

Проблема состоит в том что эти фреймверки/библиотеки вводят новые абстракции, и новые логические слои, а в этом нет абсолютно никакой необходимости.

Давайте попробуем решить эту проблему по другому, к примеру, было бы намного проще если бы мы могли указывать наши `view` непосредственно в шаблоне, как часть разметки, а их **properties** указывать просто как атрибуты:

```ejs
<div>
	<p>
		Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
		Donec mattis, turpis congue finibus suscipit, massa est convallis massa,
		ut fermentum tellus neque vitae orci.
	</p>
	<::RAD_View prop="<%= ... %>" data="<%= data.forView%>"/>
</div>
```

Такой подход решил бы множество проблем: 

* проблемы с nested view
* проблему layout'инга
* проблему передачи данных из родительских компонент в дочерние
* и, наконец, позволило бы сделать легкий и прозрачный Dependency Injection для `view`

**RAD.js** решает данную проблему именно таким способом.

> **На самом деле основным эффектом от такого типа `Dependency Injection` являеться возможность использования компонентной архитектуры при разработке приложения на `Backbone.js`**

Попробуем и мы сделать [пример пример из предидущего раздела](DOM.md) более читабильным и правильным.

## View

Для этого разделим шаблон из предидущего примера на две независимые функциональные части:

* кнопка которая подсчитывает количество кликов
* greetings widget, состоящий из поля ввода и заголовка связаного с ним.

Все правильно, эти две функциональности абсолютно не связанны друг с другом, и логично бы было разнести их в разные модули.

### javascript

Что бы не превращать проект в кашу создадим директорию `source` в которую будем складывать все исходные файлы. И вложенные папки: `source/views/greetings`, `source/views/counter` и `source/views/main`. Что бы расположить исходный код наших `view`

В каждой из папок создадим `index.js` и `template.ejs` для каждой из наших компонент соответственно. Кроме пожалуй папки `counter`, отдельный файл шаблона в ней просто не нужен.

> Вы можете конечно указывать шаблоны как строки в js файлах, выбирать вам, мы же пока покажем более развернутый пример.

Разнесите логику и шаблоны `counter` и `greetings` виджетов по своим папкам самотоятельно там нет абсолютно ничего нового, что бы не обсуждалось в прошлом разделе.

Поэтому просто приведем их листинги.

`source/views/greetings/index.js`:

```javascript
import {View} from 'RAD.js';

class Greetings extends View {
    template = require('./template.ejs');

    events = {
        'input input': 'onInput'
    };

    getTemplateData() {
        return {
            string: 'Hello, '
        };
    }

    onInput() {
        let name = this.refs.my_input.value;
        this.props.set('name', name);
    }
}

module.exports = Greetings;
```

`source/views/counter/index.js`:

```javascript
import {View} from 'RAD.js';

class Counter extends View {
    template = require('./template.ejs');

    events = {
        'click button': 'onClick'
    };

    onClick() {
        let count = this.props.get('count');
        this.props.set('count', count + 1);
    }
}

module.exports = Counter;
```

`source/views/main/index.js`:

```javascript
import {View} from 'RAD.js';

class Main extends View {
    template = require('./template.ejs');
}

export default Main
```

А `index.js` приобрел теперь совсем простой вид:

```javascript
import {publish} from 'RAD.js'
import MainView from './source/views/main'

publish('navigation.show', {
    container: '#screen',
    content: MainView
});
``` 
**На что обратить внимание:**

* так как иньекция происходит через функцию `require` по спецификации CommonJS, которую **webpack** подменяет своим аналогом внутри сбилдженого бандла, то и экспорт модулей, которые инжектяться в шаблоны (это касаеться только иньекции в шаблоны когда используеться webpack loader), должен быть произведен через `module.exports = ... ;`. Для того чтобы **webpack** смог совместить эти да события.

> Использование экспорта из спецификации *ES6* для импорта(*dependency injection*) `view` в данный момент не представляеться возможным так как компиляцию *ES6* производит **babel**.

### template.ejs

Шаблоны `greetings` и `counter` не несут в себе новой функициональности, поэтому приводить мы их не будем.

Вся новая функциональность сосредоточена в шаблоне `main` вью, в который мы вставляем наши выделенные модули.

Не углубляясь в документацию по [`Dependency Injection`](../basics/Injection.md) так как это **quick start**, мы приведем `./source/views/main\template.ejs` полностью:

```ejs
<%
var Counter = require('../counter');
var Greetings = require('../greetings');
%>
<::Greetings name="World" />
<::Counter amount="<%= 0 %>" />
```

**Проще некуда:** Все что вам необхдимо это экспортировать с помощью `require` необходимую Вам `view` и с помощью префекса `::` вставить ее в шаблон. Все атрибуты полученного кастомного тега автоматически станут properties вашей импортированной `view`.

**На что обратить внимание:**

* так же как и в предидущем пункте на то как именно Вы экспортируете и импортируете модули.
* в качестве значения атрибута `count` мы использовали запись: `"<%= 0 %>"`, что бы `0` передавался как число, а не строка.

*Основополагающей идеей, данного подхода являеться необходимость декларотивного использования `view` как элементов шаблона Вашей`view`, что в несколько раз упрощает разработку.*

> На самом деле, `Dependency Injection` в шаблоны не ограничиваеться только `view`, оно основано на иньекции любых js функций в шаблон, поэтому и чистые функции и компоненты на них основанные, тоже легко иньектируються в шаблоны. Об этом более подробно в [документации]((../basics/Injection.md)).

## Source

Исходники нашего проекта можно получить по следующей [ссылке](source/3.zip).

## Альтернативный вариант

И здесь, как и в предидущем разделе, мы немного упростим и изменим реализацию, добавив работу с разшаренным для трех `view` объектом данных:

>Стоит заметить что данный пример отнюдь не демонстрирует best практики в архитектуре, он (пример) продиктован показать, что вас никто ни в чем не ограничивает. И таже гибкость которая вам была доступна в **Backbone.js** есть и здесь. А как выстраивать архитектуру приложения решать только вам. 

```javascript
import {View, publish, template} from 'RAD.js'

class Counter extends View {
    template = template(`<button>Clicks:<%= this.data.count %></button>`);

    events = {
        'click button': 'onClick'
    };

    initialize(options) {
        this.data = options.data;
    }

    onClick() {
        this.data.count += 1;
        this.render();
    }
}

class Greetings extends View {
    template = template(`
        <h1><%= 'Hello, ' + this.data.name + '!' %></h1>
        <div>
            <input type="text" value="<%= this.data.name %>"/>
        </div>`);

    events = {
        'input input': 'onInput'
    };

    initialize(options) {
        this.data = options.data;
    }

    onInput(e) {
        this.data.name = e.target.value;
        this.render();
    }
}

class WelcomePage extends View {
    template = template(`
        <::this.inner.Greetings data="<%= this.data %>" />
        <::this.inner.Counter data="<%= this.data %>" />`);

    inner = {
        Greetings: Greetings,
        Counter: Counter
    };

    data = {
        name: 'World',
        count: 0
    };
}

new WelcomePage({el: '#screen'}).render();
```

[Исходники](source/3_alt.zip).

### На что стоит обратить внимание
Как и в предидущем варианте наши внутрение `view` указываються декларативно с помошью префикса динамического биндинга в шаблоне `::`. Но в отличии от прошлого примера, мы не пользуемся webpack лоадером и все модули у нас указаны в одном файле.

Но так как в шаблон компилируеться без замыкания, то он не будет знать ничего о дополнительных `view` которые у нас указаны в данном файле. Для того что бы передать конструкторы для внутрених `view` мы воспользовались тем что у нас в шаблоне всегда доступен контекст текущего `view`, в котором мы создали обычный объект для передачи конструкторов классов.

То есть, по факту мы использовали позднее связывание с помощью префикса `::`.

Дело в том что префикс `::` просто указывает для шаблона имя функции которая должна будет выполниться при рендеринге шаблонов, в нашем случае это конструкторы внутрених `view`.

>Так как шаблон компилируеться в изолированном от `view` контексте, то для функция которая связываеться динамически должна быть или экспортирована с помощью вебпака, описана непосредственно в шаблоне или как в нашем примере вставлена через контекст текущего `view`.
>
> Так же возможна инъекция кусков шаблонов с помощью `itemplate-loader`  для webpack, так как откомпелированный шаблон это функция. 

## Что дальше?

В [следуещей части](Components.md) мы немного упростим наш альтернативный вариант, воспользовавшись тем что можно декларативно использовать в шаблоне сторонние функции.  И разделим понятия `view` и `component`.