Порог вхождения в Angular 2 — теория и практика

  • Tutorial
Добрый день, дорогие хабра: жители, читатели, писатели, негативно-комментаторы.

В качестве вводной части и чтобы снять некоторые вопросы немного расскажу о себе. Меня зовут Тамара. Оужас, я девушка! Кого это пугает — закрывайте статью и не читайте.

Для остальных: у меня за плечам незаконченный лет 10 назад МИРЭА, факультет кибернетики. Но все эти 10 лет практики сложились таким образом, что по большей части я занималась рекламой и в перерывах случалось работать в различных стартапах, связанных с интернетом и не только.

image

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

Я покривлю душой, если скажу, что я не могу разобраться в чужом коде. Могу, на java и php могу даже какие-то простые вещи поправить. Но дальше этого мой опыт программирования никогда не уходил.

image

Но это же все не то, душа просила поэзии с чистого листа. И вот прекратив на некоторое время свою трудовую деятельность и взяв длительный отпуск для души и тела я таки решила попробовать что-то сделать с 0 и самостоятельно. Под "что-то" я понимаю свой маленький проект.

Когда думала и выбирала на чем делать, то для бэкенда остановилась на PHP. А точнее на фреймворке — Laravel.
На нем я остановилась по той причине, что для меня он показался самым низким по порогу вхождения. Мне не нравится в нем документация, так как с моей точки зрения многие моменты не раскрыты и приходится лезть в исходники, чтобы почитать комментарии. Но основные общие моменты разобраны на многих ресурсах. Laracasts как источник обучения весьма грустен. Тейлор там рассматривает все достаточно поверхностно, перескакивая с одного на другое и совершенно не углубляясь. Все по верхам.

Для фронтенда я выбрала Angular 2. Да, я знаю, что он в beta-режиме :), но мне он опять же показался логичным.
Для въезжания в Angular2 я пользуюсь их документацией, исходниками на github, чтения issue там же, stackoverflow — но там как-то все сейчас грустно — задают вопросы в основном ответы на которые есть в документации.

Ну, наверное с вводной частью буду заканчивать.
Перейду теперь к сути. Ниже я поделюсь своим маленьким опытом, что же у меня получилось и за какое время я осилила это сделать.

image

Тут не будет примеров todo и helloworld.
Я покажу маленький пример того, что я сейчас ковыряю и как у меня это работает.
В кусочке будет получение данных через api, вывод их, и отправка формы.

Настройка Angular 2 и Laravel.


Я не буду заострять на этом внимание. Для Angular 2 — вся базовая настройка проекта написана в их 5-и минутном туториале HelloWorld.
С Laravel тоже базовое создание проекта описано в документации.

Остановлюсь поподробнее только на том моменте, который меня на старте поставили в тупик.

Когда я начинала проект меня волновал вопрос взаимодействия этих товарищей в плане роутинга. А именно, если грузить Angular в папку public, то у меня лично возникли проблемы с роутингом. Так как у Laravel свой роутинг, который с роутингом Angular у меня вообще никак не совпадал, а манипуляции c отдачей нужных роутов не привели к нужному результату. При возврате через браузер на предыдущую страницу мне постоянно выбрасывалась laravelевская страница с ошибкой. Убив пару часов, чтобы подружить этих товарищей я приняла решение разнести по разным доменам api(бэкенд) и фронтенд. Как по мне, так в случае замены одной или другой части целого я не буду зависеть от незаменяемой части.
Так, что, условно сейчас я имею два проекта. Один, условно, крутится на домене: api.proect.dev, а второй на: proect.dev

Вдогонку автор sanex3339 подсказал как можно пробросить роуты Angular 2 через роутер Laravel 5.
За что ему огромное человеческое спасибо!
Теперь имеем два рабочих решения, из которых можно выбирать: разносить по доменам и разделять и властвовать, или компактно упаковать все в одном.

Так как я все-таки заявила в заголовке, про порог вхождения именно в Angular, то я не буду подробно останавливаться на API.

Быстренько сделаем бэкенд


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

Кому это надо - заглядывайте
php artisan make:model MainCategory -m

Эта команда создаст нам модель MainСategory и миграцию для этой модели.
В миграцию вставляем нужные нам строчки.

Миграция - как она выглядит
2016_02_22_135455_create_main_categories_table.php

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateMainCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('main_categories', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 255)->unique(); //это у меня будет название категории. 
            $table->string('slug', 255)->unique(); //это ссылка на эту категорию
            $table->boolean('show')->default(0); // тут статус публикации категории на сайте. Если true(1) - тогда показываем, если false(0) - нет.
            $table->timestamps();
            $table->softDeletes();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('main_categories');
    }
}


Модель - как она выглядит
MainCategory.php

<?php
namespace App\Models\Catalog;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * Class MainCategory
 *
 * @package App
 *
 * @property integer  $id $primaryKey $autoincrement
 * @property string   $name $unique
 * @property string   slug $unique
 * @property boolean  show
 * @property datetime created_at
 * @property datetime updated_at
 * @property datetime deleted_at
 */
class MainCategory extends Model
{
    use SoftDeletes;

    protected $fillable = ['name', 'slug', 'show'];

    protected $guarded = ['id'];

    protected $dates = ['created_at', 'updated_at', 'deleted_at'];

}


Ну и собственно контроллер, который со стороны php будет определять в каком виде данные получать, как их из базы вытаскивать, как запихивать их обратно. Он создается командой php artisan make:controller MainCategoryController
У меня он лежит в своей папочке с названием Catalog, обращаю на это внимание, так как дальше в роутах он обязательно проскользнет.
Так, как чтобы со стороны бэкенда не плодить ненужны папки-подпапки я решила, что в тематическом контроллере под разными названиями плодить нужные мне запросы :)

Контроллер - как он выглядит
MainCategoryController.php

<?php

namespace App\Http\Controllers\Catalog;

use App\Models\Catalog\MainCategory;
use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

/**
 * @api
 * @package     App\Http\Controllers\Catalog
 * @class    MainCategoryController
 */
class MainCategoryController extends Controller
{
    /**
     * Возвращает список всех категорий каталога со всеми полями
     * @function indexAdmin
     * @return mixed $main_categories
     */
    public function indexAdmin()
    {
        $main_categories = MainCategory::all();
        return $main_categories;
    }

    /**
     * @function createAdmin
     * Создание новой категории каталога. Доступно только в административном функционале
     *
     * @param Request $request
     */
    public function createAdmin(Request $request)
    {
        $main_category = new MainCategory;
        $main_category->name = $request->name;
        $main_category->slug = $request->slug;
        $main_category->show = $request->show;
        $main_category->save();
    }
}


Ну и последнее, что осталось сделать — это прописать пути. Вот кусочек route.php и 2 пути по которым мы и будем запрашивать нужную нам информацию.

Пути
Route::group(['middleware' => 'cors'], function() {
    Route::group(['middleware' => 'api'], function () {
            Route::group(['prefix' => 'backend'], function () {
                Route::group(['namespace' => 'Catalog', 'prefix' => 'catalog'], function () {
                    Route::get('/main-categories', 'MainCategoryController@indexAdmin');
                    Route::post('/main-category/create', 'MainCategoryController@createAdmin');
                });
            });
    });
});



На выходе мы на самом деле получаем 2 ссылки:

get: http://api.project.dev/backend/catalog/main-categories
post: http://api.project.dev/backend/catalog/main-category/create

На этом миссия по настройке бэкенд завершена.

Ура! Обещанный Angular 2.


Ну теперь начинается самое интересное.
Так как я пока еще не определилась окончательно со структурой в самом проекте и что и как на страницах буду отображать, то вот скрин того, как это сейчас у меня выглядит. Единственное, что для habra я кусочки шаблонов внесу в сами .ts скрипты, хотя у меня они сейчас вынесены в отдельные html.
image

Как я уже говорила — за исходник я брала базовую конфигурация из туториала. Поэтому тут ничего особенного нет. Ну, кроме, что main.ts я переименовала для себя в boot.ts :)

index.html
Единственное, на что здесь стоит обратить внимание, так это на то, что к базовым скриптам добавлены

<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>

Без этих товарищей не будут работать роуты и запросы-ответы к API.

Полный вариант index.html
<html>
<head>
    <base href="/">
    <title>Angular 2 QuickStart</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- 1. Load libraries -->
    <!-- IE required polyfills, in this exact order -->
    <script src="node_modules/es6-shim/es6-shim.js"></script>
    <script src="node_modules/systemjs/dist/system-polyfills.js"></script>
    <script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>
    <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="node_modules/rxjs/bundles/Rx.js"></script>
    <script src="node_modules/angular2/bundles/angular2.dev.js"></script>
    <script src="node_modules/angular2/bundles/router.dev.js"></script>
    <script src="node_modules/angular2/bundles/http.dev.js"></script>
    <!-- 2. Configure SystemJS -->
    <script>
        System.config({
            packages: {
                app: {
                    format: 'register',
                    defaultExtension: 'js'
                }
            }
        });
        System.import('app/boot')
                .then(null, console.error.bind(console));
    </script>
</head>
<!-- 3. Display the application -->
<body>
<shop-app>Loading...</shop-app>
</body>
</html>


В приложении сейчас есть 2 роута: это главная страница, на которую можно вернуться и это страница с отображением всех категорий и добавлением новой.

Роуты у меня расположены в app.component.ts. И, соответственно он же у меня является тем самым входным компонентом, который и видно в виде тэгов <shop-app></shop-app> на главной странице.

Полный вариант app.component.ts
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from "angular2/router";
import {HomePageComponent} from "./home-page/home-page.component"
import {DashboardMainCategoryComponent} from "./dashboard/catalog/main-category/main-category.root.component";

@Component({
    selector: 'shop-app',
    template: `
    <a [routerLink]="['HomePage']">Главная</a>
    <a [routerLink]="['/DashboardMainCategory']">Категории</a>
    <router-outlet></router-outlet>
    `,
    directives: [ROUTER_DIRECTIVES],
    providers: [ROUTER_PROVIDERS]
})

@RouteConfig([
    {
        path: '/',
        name: 'HomePage',
        component: HomePageComponent,
        useAsDefault: true
    },

    {
        path: '/main-category',
        name: 'DashboardMainCategory',
        component: DashboardMainCategoryComponent
    }

])
export class ShopAppComponent { }


Собственно, чтобы роуты заработали нам осталось всего-ничего — добавить соответствующие компоненты: HomePageComponent и DashboardMainCategoryComponent.

Полный вариант HomePageComponent - home-page.component.ts
import {Component} from "angular2/core";

@Component({
    selector: 'home-page',
    template: '<h1>Главная страница</h1>'
})

export class HomePageComponent {}


Полный вариант DashboardMainCategoryComponent - main-category.root.component.ts
import {Component} from "angular2/core";

@Component({
    selector: 'dashboard-main-category',
    template: '<h1>Категории</h1>'
})

export class DashboardMainCategoryComponent {}


Так, сделали. Теперь надо пойти в boot.ts и импортировать основной компонент ShopAppComponent.

boot.ts
Это самый пустой компонент в моем проекте :) У меня он ничего не делает, кроме как загружает все, что нужно из основного компонента с названием app.component.ts

Полный вариант boot.ts
import {bootstrap} from 'angular2/platform/browser'
import {ShopAppComponent} from "./app.component";

bootstrap(ShopAppComponent);


На этом с роутами мы закончили. И, если сейчас сделать npm run start, то у вас уже будет сайт на котором можно попрыгать между двумя страничками.

Предлагаю перейти к самому вкусному — давайте сделаем так, чтобы у нас загружались данные из базы.

Так, как я не люблю все мешать в одну кучу, то я разные вещи сейчас разношу по разным скриптам. Потом может я приду к тому, что у меня избыток отдельных файликов и буду рефакторить, но пока для своего удобства я делаю так как делаю.

Базовая модель MainCategory


Перво-наперво нам надо сделать простой класс — аналог Модели на php, pojo — на java.
Давайте его обзовем аутентично: main-category.ts

Полный вариант main-category.ts
export class MainCategory{
    constructor(
        public id: number,
        public name: string,
        public slug: string,
        public show: boolean,
        public created_at: string,
        public updated_at: string,
        public deleted_at: string
    ) {}
}


Все, что он делает — так это представляет нам структуру тех данных, которые мы будем запрашивать или отправлять по API.

Может возникнуть вопрос — почему даты у меня как string. Скажу честно — у меня был косяк с тем, чтобы запрашивать даты как даты. Постоянно выдавало ошибку, поэтому я пока отоложила ломание головы и пошла по простому пути.

MainCategoryService


Ладно, первый шаг сделали. Потопали дальше. Если заглянуть в ARCHITECTURE OVERVIEW Angular2, там они предлагают придерживаться той идеи, что ту часть приложения, которая что-то делает (например, авторизация, логгирование, калькулятор пошлины или, как в нашем случае — общение по API) надо называть service и выносить в отдельный файл, который мы потом будем импортировать туда, куда надо. Это необязательно, но желательно. Я так и поступила. Отсюда у меня появился main-category.service.ts

Полный вариант main-category.service.ts
import {Injectable} from "angular2/core";
import {Http, Headers, RequestOptions, Response} from "angular2/http";
import {Observable} from "rxjs/Observable";
import 'rxjs/Rx'; //без этого импорта у нас любое общение с API будет заканчиваться ошибками. Временная фича, которую обещают найти и устранить
import {MainCategory} from "./main-category";

//@Injectable - декоратор, который передает данные о нашем сервисе.
@Injectable()
export class MainCategoryService {

    constructor (private http: Http) {}

    //так как у меня по разным ссылкам запрос и отправка данных, то я сделала 2 переменные с их указанием. Если вдруг что поменяется в ссылках, то мне не надо будет разыскивать по всему документу :) Удобно
    private _getAdminMainCategories = 'http://api.shops.dev:8080/backend/catalog/main-categories';
    private _createAdminMainCategory = 'http://api.shops.dev:8080/backend/catalog/main-category/create';

   //запрашиваем все категории каталога 
   getAdminMainCategories() {
        //обращаемся к API через get
        return this.http.get(this._getAdminMainCategories)
                        //тут мы принимаем событие и возвращаем некоторые данные. В нашем случае - массив категорий в json формате
                        .map(res => <MainCategory[]> res.json())
                        .catch(this.handleError);
    }

    //создаем категорию каталога. Так как мы заранее знаем какие данные и в каком виде нам приходят, то мы указываем, что будем получать и передавать
    createAdminMainCategory(name:String, slug:String, show:boolean) : Observable<MainCategory> {
        //преобразуем данные в JSON-строку. Обещают, что потом нам эта строчка не будет нужна
        let body = JSON.stringify({name, slug, show});
        //устанавливаем нужный нам заголовок
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });

        //отправляем данные
        return this.http.post(this._createAdminMainCategory, body, options)
            .map(res =>  <MainCategory> res.json())
            .catch(this.handleError)
    }

    private handleError (error: Response) {
        //in a real world app, we may send the error to some remote logging infrastructure
        //instead of just logging it to the console
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }
}


На этом основное взаимодействие с сервером мы описали. Осталась сущая ерунда — пара компонентов и дело в шляпе!

GetMainCategories


Начнем с компонента, который получает данные: main-category.get.component.ts

Полный вариант main-category.get.component.ts`
import {Component} from "angular2/core";
import {MainCategoryService} from "./main-category.service";
import {OnInit} from "angular2/core";
import {MainCategory} from "./main-category";

@Component({
    selector: 'backend-get-main-categories',
    templateUrl: 'app/dashboard/catalog/main-category/main-category.get.template.html',
    providers: [MainCategoryService] //в качестве провайдера как раз указываем созданный нами сервис
})

export class BackendGetMainCategories implements OnInit {

    constructor (private _mainCategoryService: MainCategoryService) {}

    errorMessage: string;
    mainCategories: MainCategory[];

    ngOnInit() {
        this.getAdminMainCategories();
    }
    //обращаемся к созданному нами сервису, конкретно к getAdminMainCategories
    getAdminMainCategories() {
        this._mainCategoryService.getAdminMainCategories()
                                .subscribe(
                                    mainCategories => this.mainCategories = mainCategories,
                                    error => this.errorMessage = <any>error
                                );
    }
}


Полный вариант шаблона main-category.get.template.html
<h1>Категории каталога</h1>
<table>
    <thead>
    <tr>
        <th>id</th>
        <th>name</th>
        <th>slug</th>
        <th>show</th>
        <th>created_at</th>
        <th>updated_at</th>
        <th>deleted_at</th>
    </tr>
    </thead>
    <tbody>
   <!--Angular повторяет строку до тех пор пока у нас данные не закончатся :)-->
    <tr *ngFor="#mainCategory of mainCategories">
        <td>{{ mainCategory.id }}</td>
        <td>{{ mainCategory.name }}</td>
        <td>{{ mainCategory.slug }}</td>
        <td>{{ mainCategory.show }}</td>
        <td>{{ mainCategory.created_at }}</td>
        <td>{{ mainCategory.updated_at }}</td>
        <td>{{ mainCategory.deleted_at }}</td>
    </tr>
    </tbody>
</table>


PostMainCategory


В Angular2 есть два способа создания форм — template и data-driven. Принципиальное отличие у них в том, что в template — все проверки пишутся в самом шаблоне. Т.е. это более близко к Angular1. Data-driven — это нововведение в Angular2 и все проверки уходят из шаблона. Ну это пока то как я для себя поняла эту разницу. Боюсь, что тему я до конца не раскрыла, так как в голове по поводу этих форм еще каша. Честно сказать — второй вариант с формами мне показался проще и чище. Но с ним есть сейчас много своих косяков.

Полный вариант шаблона main-category.create.component.html
import {Component} from "angular2/core";
import {MainCategoryService} from "./main-category.service";
import {OnInit} from "angular2/core";
import {FORM_DIRECTIVES} from "angular2/common";
import {FORM_PROVIDERS} from "angular2/common";
import {ControlGroup} from "angular2/common";
import {FormBuilder} from "angular2/common";
import {Validators} from "angular2/common";
import {MainCategory} from "./main-category";
import {HTTP_PROVIDERS} from "angular2/http";

@Component({
    selector: 'backend-create-main-category',
    templateUrl: 'app/dashboard/catalog/main-category/main-category.create.component.html',
    providers: [MainCategoryService, FORM_PROVIDERS, HTTP_PROVIDERS],
    directives: [FORM_DIRECTIVES]
})

export class BackendCreateMainCategory implements OnInit {
    //сообщаем что у нас есть группа контроллеров в нашей форме и она одна :) 
    createMainCategoryForm: ControlGroup;
    mainCategories:MainCategory[];
    errorMessage: string;

    constructor( private _formBuilder: FormBuilder, private _mainCategoryService: MainCategoryService) {}

      //то о чем я писала - наши проверки вынесены из шаблона
      ngOnInit() {
        this.createMainCategoryForm = this._formBuilder.group({
            'name': ['', Validators.required],
            'slug': ['', Validators.required],
            'show': [false]
        });
    }

     //при сабмите формы отправляем данные на сервер
     onSubmit() {
        var name = this.createMainCategoryForm.value.name;
        var slug = this.createMainCategoryForm.value.slug;
        var show = this.createMainCategoryForm.value.show;
        this._mainCategoryService.createAdminMainCategory(name, slug, show).subscribe(
          main_category => this.mainCategories.push(main_category),
            error => this.errorMessage = <any>error
        );

    }


Полный вариант шаблона main-category.create.template.html
<h1>Создать категорию каталога</h1>

<form [ngFormModel]="createMainCategoryForm" (ngSubmit)="onSubmit()">
    <div>
        <label for="name">Название</label>
        <input type="text" id="name" [ngFormControl]="createMainCategoryForm.controls['name']">
    </div>
    <div>
        <label for="slug">Ссылка</label>
        <input type="text" id="slug" [ngFormControl]="createMainCategoryForm.controls['slug']">
    </div>
    <div>
        <label for="show">Опубликовать?</label>
        <input type="checkbox" id="show" [ngFormControl]="createMainCategoryForm.controls['show']">
    </div>
    <button type="submit">Сохранить</button>
</form>


К сожалению radiobutton пока шалит в Angular2 и работать может, но только после длительных плясок с бубном, так, что для своих нужд я остановилась пока на checkbox.

Осталось все нужное импортировать в наш класс DashboardMainCategoryComponent. Теперь он будет выглядеть вот так:

Полный вариант main-category.root.component.ts
import {Component} from "angular2/core";
import {FORM_DIRECTIVES} from "angular2/common";
import {ControlGroup} from "angular2/common";
import {Control} from "angular2/common";
import {FormBuilder} from "angular2/common";
import {Validators} from "angular2/common";
import {MainCategoryService} from "./main-category.service";
import {HTTP_PROVIDERS} from "angular2/http";
import {BackendGetMainCategories} from "./main-category.get.component";
import {BackendCreateMainCategory} from "./main-category.create.component";
@Component({
    selector: 'dashboard-main-category',
    template:`
    <h1>Категории</h1>
    <backend-get-main-categories></backend-get-main-categories> 
    <backend-create-main-category></backend-create-main-category>
    `,
    directives: [
        FORM_DIRECTIVES,
        BackendGetMainCategories,
        BackendCreateMainCategory],
    providers: [MainCategoryService, HTTP_PROVIDERS]
})

export class DashboardMainCategoryComponent {}


На этом мы имеем простое приложение с получением и отправкой данных на сервер.

Итоги


Если взять чистое время, которое у меня заняло написать то, что я выложила выше и заставить это работать:
Backend — 1 час 17 минут. Это не совсем чистое время, а вместе с загрузкой PhpStorm, хождениями на перекуры и отвлечениями на телефонные разговоры. Для меня это достаточно просто, так как все таки php я не первый раз вижу.
С Angular2 все сложнее.
Я никогда не копалась в JS. Нет, скриптик подключить я могла по инструкции, а вот дальше — для меня это был темный лес, в который я нос не совала. В итоге на курение доков по Angular2, JavaScript, TypeScript, вникание, написание, перепроверки, переделки у меня ушло чистых 12 часов 48 минут. Перекуры, разговоры, загрузки-перезагрузки IDE в этом времени не учтены.

Итого: IMHO Angular2 весьма опасен тем, что туда могут вот так вот, достаточно просто влезть такие блондинки как я, и даже потратив не так много времени сделать что-то большее, чем HelloWorld или же ToDo-список.

P.S. Тема статьи родилась из прочтения одного твита, где задавали вопрос — насколько высок порог вхождения в Angular2. Ну что же, можно сказать, что невысок. Все гуру могут хвататься за голову и предрекать наступление краха из-за того, что скоро полезут недоучки, которые будут писать полную ерунду, а им потом разгребать это.

P.P.S. За орфографию, грамматику, стилистику, некоторую саркастичность заранее прошу прощения, а при указании на что-то из первых трех пунктов — исправлю это :)

Важное: конструктивная критика, подсказки, указания на ошибки, неточности в понимании сути — крайне приветствуются. Я буду весьма благодарна если вы потратите немного своего драгоценного на меня.

И огромное вам спасибо, если дочитали этот пост!
Поделиться публикацией

Комментарии 144

    +1
    К сожалению порог вхождения никак не влияет на наличие нужной функциональности. Вот сегодня например выяснилось, что Angular2 не поддерживает лямбды, ни даже обычные инлайновые функции в темплейтах… пичалька большая.
      +3
      А можно с этого момента поподробнее, для общего развития: пример того, что хотели сделать?
        –3
        Ну вот например написать в шаблоне
        {{(function(a){console.log(a);})(3)}}
        не получится.
          +5
          И зачем Вам такое писать в шаблоне, если не секрет?
            –4
            Иногда так бывает удобно делать, когда функционала очень мало и выносить его в отдельный файл просто бессмысленно.
              +4
              Имхо, шаблоны должны оставаться по максимуму "чистыми" от логики. Хочется если что-то мелкое написать, можно это сделать через компонент (контроллер в Angular 1.x). Я не вижу проблемы, почему надо добавлять или менять сложившееся поведение.
                –2
                В реальной жизни оставлять шаблоны чистыми не получится. Логика все равно будет, если у вас что-то серьезнее Hello World.

                Идея собственного языка для первого Ангуляра была ужасной. Это порождает кучу проблем, ограничений и увеличивает порог вхождения. Вторая версия, если не ошибаюсь, не избавлена от этого недостатка, поэтому итог будет тем же самым.

                Кстати, выражение «бороться с фреймворком» я первый раз узнал именно читая о первом ангуляре.

                Не холивара ради, знаете Реакт? Там можно писать на JS в любом месте шаблона. И почему-то это не мешает, а только упрощает жизнь.
                  +2
                  В реальной жизни оставлять шаблоны чистыми не получится. Логика все равно будет, если у вас что-то серьезнее Hello World.

                  Мне это в жизни не мешает, если я вижу логику в шаблоне — я ее выношу в контроллер или директиву (для того они в Angular 1.x и придуманы).

                  Идея собственного языка для первого Ангуляра была ужасной.

                  Не очень понял, про какой язык речь?

                  Кстати, выражение «бороться с фреймворком» я первый раз узнал именно читая о первом ангуляре.

                  Не холивара ради, знаете Реакт? Там можно писать на JS в любом месте шаблона. И почему-то это не мешает, а только упрощает жизнь.

                  Да, я тоже узнал об выражении «бороться с фреймворком» именно в контексте ангуляра. И знаете какой я для себя вывод сделал? Люди, кто так писал, как правило, не понимали как работает фреймворк. Они не понимали структуры, использовали $rootScope где ни попадя, кидали события где только можно — короче сами себе раскладывали грабли, чтобы об них потом биться. Поэтому я считаю это утверждение людей, для которых javascript заканчивался на jquery и они старались все те подходы, которые использовались там перенести на Ангуляр. При этом, конечно, я не отрицаю проблем самого Ангуляра (например, дебаг который реализован отвратно).
                  Что касается реакта, то да, я его пробовал. Он мне напомнил ExtJs, но я ни тем ни другим не проникся. Я не увидел структуры в коде и удобного его построения (в первую очередь для последующей поддержки и переиспользования). Но это все имхо, я больше адепт Java и люблю все стройное и разделенное :)
                    0
                    > Мне это в жизни не мешает, если я вижу логику в шаблоне — я ее выношу в контроллер или директиву (для того они в Angular 1.x и придуманы).
                    И правильно делаете :)

                    > Не очень понял, про какой язык речь?
                    Имею ввиду все эти ng-директивы: циклы, условия и пр.

                    Я не призываю пользоваться Реактом. Кому что нравится, как говорится :)
                    Но мне кажется там сложнее выстрелись себе в ногу.

                    В Ангуляре 1, мне кажется, очень неудобно связывать между собой директивы, расположенные «на одном уровне», т.е. не вложенные. Может подскажете как вы такие проблемы решаете? Только без событий в $rootScope.
                      0
                      Имею ввиду все эти ng-директивы: циклы, условия и пр.

                      Ну строго говоря, они работают по спецификации HTML, т.е. на атрибутах и тегах. В нашем случае есть html (шаблоны) и есть js (логика), для связи которых нам нужен бридж. Мне сложно представить, как это можно было бы сделать иначе.

                      В Ангуляре 1, мне кажется, очень неудобно связывать между собой директивы, расположенные «на одном уровне», т.е. не вложенные. Может подскажете как вы такие проблемы решаете? Только без событий в $rootScope.

                      Рискну предложить Вашему вниманию свою статью. В рекомендациях я привел пункт 2, который подойдет для решения такой задачи. Вкратце — общение должно происходить через сервис, который будет своего рода интерфейсом взаимодействия между разными частями приложения и компонентом. Интерфейс лучше, потому что он понятен и точно инкапсулирует логику, т.е. наружу дает только тот функицонал, который нужен. При этом мы не связываем код, потому что этот сервис, можно инъектить в любую сущность ангуляра.
                        0
                        Вот. Вы правильно заметили, что нужен бридж. Это отдельный синтаксис (вспомните хотя бы track by у ng-repeat), который нужно помнить. Т.е. вы работаете с JS (а возможно и Coffe, TS и т.п.) и вам еще в довесок нужно помнить дополнительный синтаксис.
                        Если показать проект человеку, не знакомому с Ангуляр (а я показывал), он аж бледнеет.
                        Впрочем, не будем развивать холивар, а то это затянется, да и я не противник Ангуляра :)

                        За статью спасибо. Вообще так и делал, но показалось не слишком удобно, особенно когда нужно не просто разделить данные, а реагировать на их изменение. Приходится городить каллбеки и т.д. и т.п. Тот же React + Redux в этом плане просто сказка — спасают от всех проблем.
                          0
                          Вообще так и делал, но показалось не слишком удобно, особенно когда нужно не просто разделить данные, а реагировать на их изменение.

                          С реакцией на изменения будет чуть сложнее. Тут надо определится кто инициатор изменений и где и как их надо ловить. Из этого и строить этот интерфейс. Но в целом, тоже не так уж и сложно. И кстати, можно вполне обойтись без коллбеков. В директивах есть $watch (он как раз тут подойдет), в котором будут вызываться методы интерфейса для передачи значения в интересующий модуль.
                            0
                            При таких проверках большой проект будет очень медленно работать. Желательно чтобы директива не каждый раз вызывала factory.getSomeData() при изменении $scope, а более точечно. Хотя на ангуляре такое вряд ли получится.
                            Ну да ладно, у него много и плюсов )
                        0
                        А зачем вам "связывать" компоненты, расположенные на одном уровне?

                        p.s. я тут в этом хабе не так давно выкладывал статью, в которой я описывал как готовлю ангуляр 1.x я. У меня как-то никаких проблем нет, связей между компонентами на одном уровне нет, все изменения приходят сверху через биндинги.
                          0
                          И таким образом вы по сути реализуете односторонний поток.
                          А если на самом нижнем уровне я нажал кнопку и нужно изменить данные, у вас что происходит?
                            0
                            А если на самом нижнем уровне я нажал кнопку и нужно изменить данные, у вас что происходит?

                            Зависит от того, что мы хотим сделать. Если изменения должны происходить неподалеку и вверх по уровню, и мы не хотим что бы наши компоненты знали что должно происходить по этому действию — event биндинги. А так да — через сервисы меняем состояние, оно пробрасывается. А за счет всяких там uiRouter-ов и использования имутабельных объектов (ну или просто минимизация мутаций) — никакого оверхэда. Биндинги отрабатывают мгновенно, за счет отказа от ватчеров у нас нет дополнительного оверхэда и т.д. Данные просто обновляются.

                            Ну и есть еще пара десятков ситуаций в которых надо просто чуть подумать. Я же просто бью по рукам всякий раз как вижу $scope где-то кроме link директив. ну и "ивенты" ангуляра — это ивенты ангуляра, нечего нам их самим слать.

                            Но это все для angular1, в котором change detection реализован примитивно и влоб. В NG2 проблем с этим нет вообще. Оно учитывает зависимости по данными и ресолвит не весь граф состояний приложения, а только ту ветвь которая поменялась. Словом реактивщина и все такое. Ну и происходит это прозрачно для разработчика, за счет кодогенерации в рантайме (вместо универсального медленного кода генерится высокопроизводительный оптимизированный под VM специфичный код).
                              0
                              ну и "ивенты" ангуляра — это ивенты ангуляра, нечего нам их самим слать

                              А я вот не соглашусь — нет смысла тащить еще одну либу которая будет делать тоже самое что и сам angular.

                              Я же просто бью по рукам всякий раз как вижу $scope где-то кроме link директив

                              Почему? У меня в (первом приложении) чатике на angular 1.x все сообщения из websocket-а распространяются через $rootScope.$broadcast и соответственно ловятся через $scope.$on. Как следовало сделать вместо этого? (меня пока напрягает только необходимость тащить $scope в фабрики внутри контроллеров которые обрабатывают эти сообщения).
                                0
                                нет смысла тащить еще одну либу которая будет делать тоже самое что и сам angular.

                                Система ивентов в ангуляре адаптирована под конкретные уловия — древовидная структура, иерархия скоупов и т.д. Завязывать логику приложения на нее, а не сделать какую-то локализованную шину сообщений, это я считаю дурным тоном. Да, можно так делать, но повторюсь — мое код ревью этот код пройдет только в случае если приложение маленькое и всем плевать.

                                все сообщения из websocket-а распространяются через $rootScope.$broadcast

                                А у меня сервисы ничего не знают о ангуляре. Ну то есть кое-что подозревают, но минимально. Иванты $scope и т.д. это все нужно для организации жизненного цикла директив/компонентов, не более.

                                У меня к примеру по пушам из сокетов просто вызывается нужный хэндлер (хэндлеры регистрируются в провайдере сервиса нотификаций). То есть даже ивентов нет, просто еще один слой адаптеров между бизнес логикой и сетевым интерфейсом.
                                  0
                                  Система ивентов в ангуляре

                                  Никто не заставляет использовать иерархию — можно все слать бродкастом получим как раз вашу "локализованную шину" (насколько знаю, сейчас при этом все скопы уже не дергаются и проблем с производительностью нет). Кроме того, не забываем что $scope автоматически хоронит все связанные обработчики — как без этого можно обойтись в большом приложении я не знаю (удалять их вручную как раз и есть дурной тон) — это основная причина почему у меня все сделано именно так кривовато.

                                  У меня к примеру по пушам из сокетов просто вызывается нужный хэндлер

                                  Я хотел так сделать, но потом, когда появился еще один объект со своими событиями, понял что код мало того что дублируется уже в двух местах, так еще и получается по сути тот же $broadcast только с необходимостью ручного удаления обработчиков (что без деструкторов в js совсем печально).
                                    0
                                    что без деструкторов в js совсем печально

                                    Деструкторы в этом случае вам так же не помогут никак. У вас же инстанс объекта сервиса не уничтожается.

                                    как без этого можно обойтись в большом приложении я не знаю

                                    Обработчики хранятся в коллекции. Удаляем коллекцию — пропадают ссылки на обработчики. Ничего "писать" не надо, сборщик мусора же.

                                    Короче я могу сказать только одно — просто не используйте $scope. Вообще. И тогда жить с ангуляром становится в разы приятнее.
                        0
                        Мне это в жизни не мешает, если я вижу логику в шаблоне — я ее выношу в контроллер или директиву (для того они в Angular 1.x и придуманы).

                        Это очень трудно сделать если шаблон собирается по кусочкам на сервере. Сервер тупо не имеет доступа к контроллеру или директивам.
                          0
                          Это очень трудно сделать если шаблон собирается по кусочкам на сервере.

                          А зачем так в принципе делать? Вот серьезно?
                            0
                            Чтобы уменьшить количество требуемых телодвижений для создания чего либо. У нас UI это преимущественно формы (текстовые поля, списки), поэтому их можно достаточно просто генерировать. Мы бизнес логику делаем на c# обьектах и биндингах на модель. Из этой информации мы потом создаем ангуляр шаблон уже со всем готовым: лэйблами, валидаторами, етс.

                            Так вот биндинги это C# выражения которые транслируются в angular/javascript выражения. Простые типа [disabled]="m.A && m.B" работают на ура, а вот вышеуказанный find нет.

                            Эти же биндинги потом используется для автоматической серверной валидации приходящего запроса.
                  0
                  Ну вот например вы в курсе что в ES6 добавили метод find для массивов. Этот find принимает коллбэк с помощью которого можно искать элемент в массиве по произвольному признаку.

                  Например у меня есть массив аккаунтов, и мне надо достать баланс по id. В шаблоне можно написать
                  m.accounts[#i].balance
                  

                  но только если есть #i. Если же мне надо делать поиск по id, то нужно делать
                  m.accounts.find((a) => a.id == myId).balance
                  


                  можно конечно вынести поиск в модель, но это не всегда удобно, и иногда вообще невозможно (когда шаблон собирается из кусочков на сервере).
                    +1
                    Если вам надо сделать поиск по ID то вы должны его делать не в шаблонах а в контроллере. И у меня нет ни одного кейса при котором это нельзя сделать или по каким-то неведомым причинам это неудобно.
                      0
                      У нас шаблон собирается на сервере из конфигурации. Хотим уменьшить количество мест где надо править код. Для этого было бы очень удобно вставлять небольшие инлайновые функции. А так получается, что сегодня нам надо искать по id, а для этого надо менять и webapi контроллер который выдает шаблоны, и ангуляр контроллер который байндится на клиенте. Завтра надо будет искать не по id, а по чему нибудь ещё, и опять менять код в нескольких местах.
                        0
                        Хотим уменьшить количество мест где надо править код.

                        Для этого можно было бы сделать простой RPC на сервере, работающий с данными, и формы вынести целиком и полностью на клиент. Тогда все было бы просто, удобно, и не нужно было бы плодить эти дикие кастыли.
                          0
                          Тогда не получим автоматическую серверную валидацию, и все равно код плодить придется.
                            0
                            мне вообще не понятно зачем вы брали angular2 для такой задачи, но повторюсь — в том же ng2 должна быть штука под названием form model, в этом случае все правила валидации и тд. определяются там. А это уже можно как-то генерить и подгружать.

                            А логика в темплейтах — это автоматический проигрыш и вообще становится непонятно зачем брать ангуляр для этого.
                              0
                              Это было не моё решение. Но если абстрагироваться от этого чистые шаблоны как идея хорошо, но не жизнеспособно в боевых условиях. Не зря же разрабы добавили некоторую поддержку логики. Мои претензии лишь к тому что они не довели её до конца.
                                0
                                но не жизнеспособно в боевых условиях.

                                3 года с ангуляром. Что я делаю не так?

                                Не зря же разрабы добавили некоторую поддержку логики

                                Не зря же добавили null как тип данных в наши языки программирования, ведь так? Вы видимо не застали те холивары которые происходили в трекере ангуляра, когда народ срожался с любителями логики в шаблонах, которым уж очень хотелось иметь тернарный оператор там.

                                Суть шаблонов в ангуляре — это декларативное представление, абсолютно чистое и прозрачное. И как только логика из контроллеров вытекает в шаблоны, все становится уже не так красиво, и начинается сошествие в ад.
                          0
                          Вместо сборки шаблона на сервере сериализуйте эту вашу конфигурацию в JSON, передайте клиенту и раздайте её директивам/контроллерам. Пусть они решают, что конкретно сделать на основе этих данных. Директивы сами могут генерить себе нужные шаблоны, динамически на основе входной конфигурации. Серверу вообще негоже знать о том, кто и как отображает его данные, он должен лишь отдать их и сообщить, какие данные ожидает взамен. Если вы захотите кардинально поменять поведение на клиенте (скажем, не дизейблить контролы, а менять их видимость, или показывать сообщение, или вообще выкинуть Ангуляр и воткнуть что-то другое), то вам нужно будет поменять лишь клиентскую компоненту, и не нужно будет трогать сервер.

                          То же самое для валидации — сделайте сервисы валидации на клиенте и на сервере, вынесите правила валидации в отдельную модель/конфигурацию, передавайте её обоим сервисам как параметр. Пусть клиент делает свою часть как он умеет, а сервер — свою, и друг о друге им знать не надо.
                    0
                    Ну вот, типичный пример блондинки.
                  +6
                  Потому что шаблоны в ангуляре декларативные.
                    0
                    Ну на самом деле они там делают лексический анализ, строят AST тэгов. Могли бы и добавить поддержку javascript кода, тем более что они уже сделали ограниченную поддержку некоторых ключевых слов, например "if", "else".
                      –2
                      Какая у вас основная специфика работы? Frontend / backend? Как долго вы с Ангуляром знакомы? Судя по вашим эмоциям относительно Ангуляр 2 вы с первым не работали.
                        +2
                        Каким таким эмоциям?
                    +5
                    инлайновые функции в темплейтах

                    Да вас святой водой окропить надо.
                      +2
                      А еще он кофе не умеет готовить и посуду мыть. Нафиг такая недоделка нужна кому-то...
                        +3
                        Извиняюсь за оффтоп, но не могу не спросить. Ваша замечательная библиотека https://github.com/tamtakoe/oi.select планирует дальше развиваться? Мы ее используем в своих проектах, но хотелось бы решение некоторых тикетов. И кстати спасибо за труд :)
                          0
                          Планирую. Последние месяцы катастрофически не хватало времени. Только вчера в Россию вернулся. Отойду немного и примусь разгребать ишью
                      +7
                      Мне кажется, вся проблема в том, что вы решили изучить Angular 2 для того, чтобы изучить Angular 2. При этом у вас в голове есть какие-то свои задачи, свои требования, свой подход, и все это очень сильно отличается от того, что предлагает фреймворк.

                      У меня было иначе. Когда я открыл 5-минутный урок, перейдя по ссылке с какой-то новости на Хабре, то понял: вот оно! Это именно то, что я искал. То, что я сам хотел завелосипедить (и сделать при этом хуже, чем вышло у них).

                      Используйте инструменты по назначению и не стреляйте из пушки по воробьям.

                      P.S. Стиль статьи напомнил мне материалы на Django Girls :-)
                        +3
                        P.S. Не читала, не знаю, открывать не буду :)

                        Я не знаю откуда у вас сложилось такое представление. Но я не буду просить цитат :)
                        И я искренне не понимаю как вы не зная моих задач уже судите, что все это отличается от того, что предлагает framework. Вот тут мне бы уже хотелось услышать ваши логические рассуждения :)

                        Да, у меня в голове есть свои задачи. Вы совершенно правы. Точнее задача-то одна — сделать проект, который делаю.
                        Прежде чем хвататься за Angular 2 я попробовала сделать минимальные примеры на React, Ember, Backbone, VueJs, Angular1.4 и даже Aurelia потестила. Решала ту же задачу, которая здесь описана в статье.
                        Не являясь программистом я только на решении определенной проблемы могу понять насколько легко или сложно дальше у меня этой пойдет и какие подводные камни есть. Пример HelloWorld и ToDo списки так любимые — не показательны в силу их отдаленности от столкновения с более-менее реальным миром.

                        Но, подозреваю, что вам не интересен мой ответ, вы судите с позиции какой инструмент для своей работы вы бы хотели завелосипедить, а я сужу с позиции — какой инструмент лучше всего мне помогает велосипедеть свой проект. И какой инструмент позволяет мне не тратить месяцы на то, чтобы понять принцип работы этого самого инструмента.
                        При условии, что инструментов много, они растут как грибы после дождя, правда погибают тоже достаточно быстро, то можно свой проект пичкать постоянно чем-то новым. Я придерживаюсь того, что внедренние сторонних фич оно как правило грозит тем, что в момент, когда разработчикам надоест с ними возиться — это будет неприятный казус и потому, выбираю минимально-необходимое кол-во инструментов. Вот потому в статье Angular2 (и даже не JS), потому тут нет React c его просто безумным количеством библиотек на каждый чих, на которые нужно много времени на изучение, нет Ember и так далее. А есть то, что самодостаточно без различных дополнительных танцев с бубном.
                        Но это мой взгляд и это для меня так.
                          0
                          В таком случае, я неверно интерпретировал ваше отношение к фреймворку.

                          Прежде чем хвататься за Angular 2 я попробовала сделать минимальные примеры на React, Ember, Backbone, VueJs, Angular1.4 и даже Aurelia потестила. Решала ту же задачу, которая здесь описана в статье.

                          Для такой задачи я бы из списка выбрал Backbone или первый Angular. Но если вы действительно копались в React, то философию, наверное, поняли.
                            0
                            Первый Angular медленно но верно подводят сейчас ко второму. 1.5 если посмотреть — туда уже и частично роутинг пытаются впихнуть улучшенный и ведут по написанию к стилю angular2.
                            Но не срослось у меня с ним, так как для моего понимания — двойка более структурированная. Мне в ней проще ориентироваться, потому, что для меня она легко читается и я мало времени трачу на то, чтобы понять откуда и куда растут ноги.
                            C backbone то же самое, что и с react — для меня это оказалось сложной задачей — вмешивать разметку в срипт.
                            Такая методика у меня стойко ассоциировалась с женской логикой — она есть, но понять ее невозможно.
                            Я уже в течении трех месяцев провожу эксперименты. Я долго решала на чем делать бэкенд, с прицелом на будущее. И изоморфный meteor пощупала. Не понравилось, что там mongo. Хотя они сейчас и собираются внедрять graphql, но это тоже все еще неясно и непонятно как будет работать. Помучила Spring. Он чудесен с моей точки зрения, но активное внедрение множества компонентов, которые дублируют друг друга — это ад. Плюс не все четко отлажено, и у меня начали вылезать баги с передачей-получением запросов. То кодировка шалила, то еще что-то.
                            В плане api под backend был интересен sailsjs. Но, к сожалению у него достаточно неповоротливые разработчики и некоторые баги они очень долго не фиксят. Плюс одна единственная книжка по этому фреймворку и не очень понятная для меня документация свели на нет мой интерес.
                            И это то, что я сейчас вспомню, что я тестила все по той же схеме :)
                            Так как воспитывалась я преимущественно папой и в квартире, которая больше напоминала сервисный центр, чем квартиру, то перебрать варианты, попробовать, поменять местами, снова попробовать, разобрать, собрать, включить, потом поискать еще более оптимальный вариант решения — это мой вариант поиска решений. И, когда я писала статью я правда пыталась показать, что простая задачка из простой, но реальной жизни может быть решена достаточно быстро. а при условии отсутствия навыков я считаю, что это вообще спринтерский забег.
                              0
                              Для бэкенда, если js смотреть хороши koa.js — там нормальная асинхронность через async / await. И loopback — там обычные rest api описывается просто декларативно. В плане фронтенда интересен react native, раз вы и так по краю ходите, легко будет портировать проект на мобильники.
                                0
                                koa смотрела уже под занавес всех экспериментов. Каюсь, но запала в нее вникать уже не хватило.
                                Loopback тоже смотрела. Не помню что меня в нем остановило. Что-то точно было. Может не то место и время, может мало примеров, может быть отсутствие чего-то нужного. Я к нему 3 раза пыталась подступиться. Не нашли взаимности. А потому с бэкенд пошла по пути наименьшего сопротивления в итоге.
                                ReactNative не смотрела. По краю я уже завязала ходить. Я уже доя себя остановилась на определенном стэке, так, что дальше тут в глубину буду копать.
                                  0
                                  Если в плане обучения — то лучше всего loopback, он вас хорошим паттернам научит. Там уже есть вся структура api, правильная иерархия url и т.п. Вам этого нехватает.
                                    0
                                    Не буду спорить про иерархию. С этим есть проблема :)
                                    Я уже чувствую, что что-то идет не так. Но пока не могу сформулировать, что именно.
                                    Чтение литературы по REST и как оно должно быть у меня почему-то оставляло привкус того, что это не очень удобно, не совсем вписывается в мое понимание "идеального" мира.
                                    Я пока экспериментирую как оно должно быть с моей точки зрения. Думаю, что через какое-то количество времени приду к некоторому пересмотру.
                            0
                            Во-первых, спасибо за статью.

                            Поделюсь своим опытом c Angular2.

                            В своё время, я начал делать свой персональный проект с Angular 1 и на тот момент — это был самый простой и лёгкий для понимания путь, как для backend-разработчика. В конечном итоге, Angular 1 лишил меня страха писать под вэб, за что ему большое спасибо. Потом, когда пришла эра React — я долго ходил вокруг, да около, много сложного и куча разнообразия, в конечном итоге теряешься, что выбрать, так я его и не смог понять, ждал выхода бэта Angular2 и начал переходить на него...

                            И тут, всё начало не срастаться (с учётом того, что мой проект на coffeescript + jade, большую часть кода я планировал оставить, да и coffeescript по-прежнему является моим выбором для фронтэнда). Начал изучать Angular2, но без TS, мне нужен был именно Javascript, чтобы без магии переводить его в Coffeescript. Документация совершенно не полная, из 16 отделов для TS в JS было всего 4, даже главы объясняющей архитектуру не было, без которой было сложно двигаться. Примеры из этих 4 глав на половину не работали, подключались какие-то библиотеки помимо Angular-а, непонятно зачем. В конечном итоге, потратив дня 3 на попытки разобраться самому, я расписал примеры чего, я хочу видеть, и заказал у фрилансера через upwork пример рабочего приложения, получил его через два дня с решением, что смогу сам перевести на Coffeescript и подключить build систему. Помимо этого там был магический фаил, который создавал абстракцию для эмуляции чего-то похожего на декораторы в Typescript-е.

                            В конечном итоге, потратив более 30 часов и дневную работу фрилансера на Angular2, читая хабрахабр я наткнулся на VueJs, мне очень понравилось начало, примеры оказались проще, чем у Angular2, а я продолжал читать о Vue, легко находил ответы на свои вопросы в документации на классическом Javascript, который я без труда мог перевести в Coffeescript. С помощью Vue скрипта я создал сразу проект, легко модифицировав пример с Jade и Coffeescript (а компоненты .vue — это вообще оказалось гениальное решение, держать шаблон с Jade и код в Coffeescript в одном файле и стиль к шаблону в том же файле). В конечном итоге, где-то за 3 вечера я сделал на Vue(не использовав его до этого) нужный мне прототип.

                            Самое интересное, что именно для Vue была статья, которая объяснила мне популярную архитектуру под React и объяснила, как её легко и при необходимости можно использовать с Vue.

                            Ещё, немаловажная отличительная особенность — скорость ответов. Когда у меня был вопрос к Angular2 — то он висел там две недели(а дальше я перестал проверять) без ответа, как и десятки других вопросов. Когда что-то не получалось с Vue, ответ пришёл в течение 1 часа, я и не ожидал так быстро.

                            В конечном итоге, простота Vue + гибкость настройки под себя + в отличие от React есть стандартные библиотеки для всего, что нужно, и они очень легко подключаются и работают + коммьюнити, которое в отличие от Angular2 отвечает на вопросы(я уже не говорю про скорость) — сделали мой выбор на Vue окончательным. И учитывая, с какой простотой я подключил jade и могу писать jade разметку и код компонента в одном файле в разных блоках, то даже не представляю как и когда это будет возможно в Angular2, всё-таки Vue здесь технически проблему решил пока намного более гибким способом (по моему личному мнению).

                            Всё было бы по-другому, если бы я не шёл бы на перекор TypeScript-у, как поступили Вы. Но и поэтому мне был бы интересен ваш опыт с VueJS, чем он оказался хуже Angular2.
                            +3
                            P.S. Почитала, но стремилась все таки, чтобы больше напоминало это:

                            осторожно - картинка

                            +3
                            Люблю такое изложение информации подкрепленной кодом / примерами.
                            Легко и интересно читать.
                              +7
                              Боже, спасибо вам за бальзам на мое сердце!
                              Не знаю как у других, но я искренне боялась писать на хабр.
                              Коленки до сих пор дрожат :)
                              0
                              И заранее приношу извинения всем, кому мне так хотелось бы поставить плюсик в комментарий — я не успеваю поймать тот момент, когда моя карма это позволяет :)
                                0
                                Странный у вас профиль — приглашена более чем на полгода позже, чем зарегистрирована. У меня, например, логично — сначала приглашен, через полчаса зарегистрирован.
                                  0
                                  Не обращала на это внимания. Удивительный сбой, потому, что я прекрасно помню время, место и какие дела я отложила, когда мне пришло приглашение. И было это в 2012 году :)
                                    +2
                                    А что странного? Я приглашен через полтора года после регистрации, как написал в песочницу, так и приглашен, а до этого ридонли.
                                      0
                                      Ну я и не регистрировалась и не писала до того момента, как меня пригласили. Так, что в моем случае это правда странно.
                                        0
                                        Тогда извиняюсь:)
                                          +1
                                          Да тут не за что :)
                                          Но вообще интересно. Почему-то в моей голове до сих пор есть убеждение, что зарегистрироваться можно было только имея инвайт.
                                          А вы вот сейчас мне обратное показали.
                                          Теперь вот вместо сна буду думать почему же я думала неправильно :)
                                            +1
                                            В то время, когда вы регистрировались, не было read-only регистрации. Так что да, только по инвайтам: личным или через песочницу. Хотя, вы уже и так либо выспались, либо не выспались, я думаю. :)
                                              +1
                                              До сих пор второе :)
                                              Ладно, значит хабр продолжил традицию — на мне вылезают везде баги :)
                                              И понимайте как хотите ))))
                                              Сорри за оффтоп
                                    +1
                                    Очень многие кто полюбили Angular 1.x не могут спокойно перейти на 2.x что очень и очень странно. Кто то кричит что 2ка — ужасна. Кто то что нет нужно. А там временем — http://thenewstack.io/google-preps-angular-2-final-release/
                                      0
                                      А то, что люди полюбившие первый ангуляр не хотят перейти на реакт вам не кажется странным? Это разные технологии. Двусторонее связывание проще и удобнее, односторонее "правильнее" и может давать преимущество в сложных проектах.

                                      В целом все эти правильности и прочие тренды типа компонентов, es6 / ts и т.п. имеют смысл только в больших проектах, разрабытываемых распределённо. А для всяких маленьких магазинчиков и т.п. (коих большинство) — это оверинжениринг чистой воды.
                                        0
                                        Двусторонее связывание проще и удобнее, односторонее «правильнее» и может давать преимущество в сложных проектах.

                                        А можете какие-то аргументы привести? Просто интересно, чем это one-way связывание правильнее two-way?
                                          0
                                          А посмотрите просто историю как фейсбук придумали реакт. Насколько я помню, у них там какой-то рассинхрон в юай был. Одностороннее связывание решило эту проблему.
                                            0
                                            В таком случае, это не из разряда "правильное/не правильное". Смена подхода просто помогла решить проблему фейсбука в своем фреймворке, вот и все.
                                            Вопрос не праздный я задавал. Мне тут с пеной у рта доказывали, что one-way биндинг это костыль, чтобы ангуляр работал быстрее. Теперь вот оказывается, что one-way биндинг это "правильно"… Во всех этих спорах я не вижу ни одного аргумента, который смог бы принять, к сожалению.
                                              0
                                              Костыль для скорости — это one-time binding в первом ангуляре, который {{:: foo }}. А one-way data flow — это архитектурное решение.

                                              Насколько я понимаю абстрактная проблема с двусторонним связыванием та же, что и с глобальными переменными. Есть у вас какая-то переменная в VM которая связана с несколькими элементами UI и может меняться с сервера, допустим. И вот эти элементы и сервер одновременно её меняют, как это разрулить? А никак, т.к. логика связывания неявно зашита где-то в глубинах фреймворка.

                                              Меня лично это проблема не беспокоит, т.к. ничего такого сложно-связанного нету. Но если бы было, я бы задумался об one-way-flow.
                                                0
                                                Костыль для скорости — это one-time binding в первом ангуляре, который {{:: foo }}. А one-way data flow — это архитектурное решение.

                                                А в чем разница? Сам React пишет "React's one-way data flow (also called one-way binding) keeps everything ..." По мне, так это одно и то же. В ангуляр это добавили не как костыль, а как решение проблем с подходами двустороннего связывания (там, где оно не требуется).

                                                Насколько я понимаю абстрактная проблема с двусторонним связыванием та же, что и с глобальными переменными. Есть у вас какая-то переменная в VM которая связана с несколькими элементами UI и может меняться с сервера, допустим. И вот эти элементы и сервер одновременно её меняют, как это разрулить? А никак, т.к. логика связывания неявно зашита где-то в глубинах фреймворка.

                                                Не встречал такого мнения, заберу в копилку. Может кто то сталкивался уже с такой проблемой? Имхо, она решается достаточно просто (обычные merge-стратегии).
                                                  0
                                                  Разница в том, что one-time binding не предполагает последующего изменения отрендеренного хтмл, а one-way предполагает.
                                                    0
                                                    она решается достаточно просто

                                                    Речь не о том, как её решить, а о том, что эта проблема заложена в самой архитектуре two-way, а в one-way её нету.
                                                    0
                                                    И вот эти элементы и сервер одновременно её меняют, как это разрулить?

                                                    В js "одновременно" невозможно в принципе — он однопоточный по своей природе...
                                                      0
                                                      Вы не поняли о чём речь или находите слово недостаточно корректным?
                                                        0
                                                        Да, оно некорректно, кроме того вам в любом случае придется решать чье значение более приоритетно — то что пришло с сервера или то что изменилось локально.
                                                          0
                                                          Вот о том и речь, что с двусторонним связыванием у вас нету возможности это решать. У вас есть только переменная во вью-модел, которая может спонтанно измениться из нескольких источников.
                                                      0
                                                      Давайте я вам расскажу про правильный two-way биндинг.

                                                      Пусть у нас есть две компоненты:

                                                      1. Владеющая — панель информации о пользователе.
                                                      2. Владеемая — поле ввода имени пользователя.

                                                      Если мы хотим реиспользовать поле ввода, то мы должны абстагировать его от конкретной бизнес модели. Чтобы редактировать таким образом можно было хоть имя пользователя, хоть фамилию, хоть кредо.
                                                      так вот, у владеющей компоненты в том или ином виде есть 3 изменяемых свойства: имя, фамилия, кредо. И ей необходимо создать 3 вложенные поля ввода так, чтобы каждое редактировало соответствующее свойство.

                                                      Напомню, всё это мы затеяли, чтобы реиспользовать код и упростить разработку. Поэтому подход реакта, где для каждого поля таки придётся написать уникальный обработчик изменения (причём аж в 3 местах: там где привязываем обработчик абстрактного события (onclick), там где обрабатываем стандартное и кидаем специфическое (UserNameChanged) и там где ловим специфическое и вносим изменение) — не решает проблему копипасты, а усугубляет её.

                                                      Проблема ангуляра в том, что у него реактивность односторонняя: от модели ко вьюшке всё реактивно, а в обратную сторону делает только один "хоп" и застревает, так как ангуляр не понимает откуда пришли изменения. А в обратную сторону тоже необходимо их реактивно перекидывать к источнику данных. При этом, если в прямом направлении состояние было вычеслено как функция от других состояний, то должна быть и функция, которая проделывает обратную операцию. Например:

                                                      Прямое направление: получили данные пользователя с сервера -> соединили имя и фамилию -> вывели в поле ввода.
                                                      Обратное: пользователь изменил строку текста -> распарсили её и обновили свойства "имя" и "фамилия" модели -> отослали патч на сервер.

                                                      Получилось немного сумбурно, но суть в том, что свойство — это некоторый канал, через который значение можно вытянуть, но можно и протолкнуть в него новое. А как он там реализован — нас не волнует. Это может быть прямая запись в поле объекта, а может быть проксирование к другому.
                                                      0
                                                      По тестым коих великое множество, что react что angular не самые быстрые решения. Очень хорошие результаты показывает backbone + incremental dom.

                                                      (Результаты можете погуглить или посмотреть что делал jridgewell )
                                                0
                                                А почему кто-то должен переходить с Angular 1.x на Angular 2? Это совершенно разные фреймворки, у которых общей кодовой базы почти нет, если не считать бекпортированного роутера и нескольких фич в 1.5. С таким же успехом можно переходить на React или Ember.
                                                0
                                                У меня сейчас такая ситуация — год разрабатывал на Angular 1.* и нужно бы куда-то переходить: либо Angular2, либо React. Я понимаю, что Angular2 связан с Angular1 только названием, но пугает не это, а отсутствие инфраструктуры — пока рожался Angular2 все кто мог ушли на React и основали там довольно внушительное сообщество. Поэтому переходя сейчас на Angular2 есть риск остаться белой вороной, если ты, конечно не работаешь в Microsoft — они могут позволить себе создать сообщество вокруг чего угодно.
                                                  +1
                                                  Берите Эмбер. Я ниже привел пример кода на нем, смотрите как красиво.
                                                0
                                                А чем описанная задача сложнее todo-листа не пойму?

                                                Вообще, ожидал увидеть некоторую кривую вхождения. Проблема же (с первым ангуляром, допустим) была не в том, что сложно освоить азы. Сложности начинались дальше. Грубо говоря, кривая вхождения была экспоненциальной — чем дальше тем сложнее.
                                                  0
                                                  HelloWorld — это из разряда тестирования мотошлема на производстве в идеальных условиях и без боковых ударов.
                                                  Пример, который дает представление о некотором взаимодействии системы — это из разряда Sharp-testing — это уже не идеальные условия, а условия приближенные к реальным ситуациям. Извините за аналогию, но спросоня ничего другого в голову не приходит. Это краткий ответ на ваш вопрос — в чем отличие.
                                                  Ко второй части — я в начале бреющего полета. В конце подведу итоги. Но в моем случае мерилом сложности-простоты является затраченное время на реализацию. Не тупой копипаст, а именно с пониманием что и как работает и что же я такое понатворила. Если вы поделитесь своим видением того как правильнее было бы раскрыть заголовок, то я учту это на будущее для работы над ошибками.
                                                    0
                                                    helloWorld — это же не todo-list. А последний это как раз и есть то, что вы описываете в статье — простенькое взаимодействие с сервером. Совершенно на любом фреймворке это будет выглядеть просто. Случай очень простой. Разница между фреймворками проявится при усложнении системы.

                                                    Вот тут умный человек очень хорошо рассказал зачем все эти рекаты и вторые ангуляры нужны, очень рекомендую, тут именно суть, а не свистелки: https://www.youtube.com/watch?v=DCeNCr2tKOI
                                                      +2
                                                      Я воздержусь от холиваров на тему удачности-неудачности примера. Скажу так-для меня этот пример более информативен, чем todo для выбора инструмента.
                                                        +1
                                                        При чём тут холивар? Разве я отстиваю какой-то другой пример? Я же вам привожу конкретные аргументы того, что функционал вашего примера — это подмножество функционала todo-листа.

                                                        В todo есть: получение коллекции, создание элемента, изменение элемента, удаление элемента. У вас только первые два пункта.
                                                  +1
                                                  А есть ли какие то принципы расположения файлов? А то не понятно почему модель лежит в папке dashboard
                                                    +1
                                                    Есть. Так как это кусочек самого начала проекта, то dashboard будет включать в себя все, что будет относиться к работе админки. Поэтому да, выглядит странно со стороны сейчас. Я могу за выходные привести эти кусочки в порядок и отдельным моментом выложить на github, если есть интерес к этому.
                                                    0
                                                    многие моменты не раскрыты и приходится лезть в исходники, чтобы почитать комментарии.

                                                    Это вообще какой-то тренд в последнее время. Никто не хочет тратить время на написание документации: "Если после урока у вас остались вопросы вы всегда можете посмотреть в исходники и понять, что идёт не так."

                                                    Простые вещи разжёвываются в документации, а в сложные отправляют "посмотреть код".
                                                      0
                                                      А что не так? Написание документации, и особенно всех неочевидных и сложных вещей отнимают огромное количество времени, но еще больше отнимает её обновление… Думаю, говорить о том насколько плоха устаревшая документация не нужно? Поэтому проще действительно сразу поглядеть исходники — это помогает лучше понять используемый фреймворк и здорово прокачивает скил.
                                                        0
                                                        Я встречал хуже. Есть документация — копируешь код примера — не работает. Жмешь на LivePreview — работает.
                                                        Оказалось, что код примера в документации и код в LivePreview чуть-чуть отличался. Только вот дойти до этого пришлось самому.
                                                          0
                                                          Не поняла немного. Документация. — что в данной статье документация?
                                                          Я специально привела скрин структуры, так как не выложила исходники на гит. Исходники выложу. Структура останется та же. Если скопировать весь код отсюда в той же структуре что есть — оно будет работать. Так как это честная копия работающего кусочка.
                                                          Скрин прикладывала именно из-за некоторого бардака в файлах. Вынужденный рабочий бардак.
                                                          Исходники предлагаю выложить с приведенной впорядок структурой и под это уже поправить статью.
                                                          Комментарии в коде лично для меня удобнее, чем листать по 100 экранов в поисках, где это описывали.
                                                          А теперь — что в итоге улучшить? Как понятнее сделать? ))))
                                                          0
                                                          Когда я начинала проект меня волновал вопрос взаимодействия этих товарищей в плане роутинга. А именно, если грузить Angular в папку public, то у меня лично возникли проблемы с роутингом. Так как у Laravel свой роутинг, который с роутингом Angular у меня вообще никак не совпадал, а манипуляции c отдачей нужных роутов не привели к нужному результату. При возврате через браузер на предыдущую страницу мне постоянно выбрасывалась laravelевская страница с ошибкой. Убив пару часов, чтобы подружить этих товарищей я приняла решение разнести по разным доменам api(бэкенд) и фронтенд. Как по мне, так в случае замены одной или другой части целого я не буду зависеть от незаменяемой части.
                                                          Так, что, условно сейчас я имею два проекта. Один, условно, крутится на домене: api.proect.dev, а второй на: proect.dev

                                                          Так как я все-таки заявила в заголовке, про порог вхождения именно в Angular, то я не буду подробно останавливаться на API.

                                                          Я пришел к такому же выводу почти сразу. Точнее сразу после того, как не смог перейти сразу на нестартовый эндпоинт.
                                                          И да, разделение на две части имеет свои полезные бонусы.
                                                          Однако есть минус: CORS. Когда UI запускается на другом домене, необходимо настроить API сервер для разрешения Cross-Origin Resources Sharing.

                                                          У вас такая проблема возникла? Мне кажется вы зря решили опустить детали реализации серверной части.
                                                            0
                                                            Да, вы правы. Это проблема вылезла. Но решилась плагином laravel/cors.
                                                            +4
                                                            По сравнению с Ember, Angular выглядит как болото. Какая то смесь кода, темплейтов, структур с настройками, куча импортов, ручная настройка запросов для модели.

                                                            Вот как на эмбер выглядит роут для новой модели:

                                                            import Ember from 'ember';
                                                            
                                                            export default Ember.Route.extend({
                                                              model: function (params)
                                                              {
                                                                return Ember.RSVP.hash({
                                                                  child: this.store.createRecord('child'),
                                                                  parent: this.modelFor('parentRouteName');
                                                                });
                                                              },
                                                            
                                                              resetController: function (controller, isExiting, transition) {
                                                                if (isExiting) {
                                                                  controller.get('model.child').rollbackAttributes();
                                                                }
                                                              },
                                                              actions: {
                                                                save: function(parent, child)
                                                                {
                                                                  let self = this;
                                                            
                                                                  child.set('parent', parent);
                                                                  child.save().then(function () {
                                                                    self.transitionTo('some.route', child.get('id'));
                                                                  });
                                                                }
                                                              }
                                                            });

                                                            В темплейте данные модели биндятся к контроллам примерно так:

                                                            {{input type='text' value='model.child.parameter'}}

                                                            И ничего не нужно фреймвоку объяснять про формы, апи, провайдеров и другие лишние штуки.
                                                              +1
                                                              На самом деле сейчас в Ember тот еще разброд и шатание (сам пишу на нем с 1.3).

                                                              В идеале, в вашем примере нужно:

                                                              • использовать

                                                                setupController(controller, models) {
                                                                  controller.setProperties(models);
                                                                }

                                                                чтобы перестать использовать model. в шаблонах (deprecated)

                                                              • input использовать согласно DDAU (ох уж эти любители акронимов) и с <> скобками

                                                              • rollbackAttributes пока что не умеет работать с belongsTo / hasMany

                                                              А так, куча вещей помечено deprecated, но при этом замены пока нет.
                                                                0
                                                                1. Найн. Model используется для возвращения модели. Потребляющий метод распознает если возвращаемый объект promise и продолжает работу после того как он отрезолвит его. setupController нужен для дальнейшей настройки контроллера, если нужно.
                                                                2. Это принцип работы Ember. Благодаря этому, ответственность за объекты несет только route. Треугольные скобки в стадии разработки и кроме эстетического удовлетворения мало чего меняют. Единственное что мне про них известно, так что биндить свойства нужно будет через mut.
                                                                3. Да, но как видите я добавляю отношения как раз перед сохранением. Если так это не обойти, то можно использовать связку setupController и resetController. Согласен, не очень удобно, но это пара коротких строк, а не то полотно как в Angular.

                                                                Я сейчас сижу на 2.4бета у меня ни одного депрекейшена. Проект из 3 аппликаций и одного общего аддона.
                                                                  0
                                                                  На счет первого, в дальнейшем не будет доступа через model, так что имеет смысл уже не писать через него, а делать напрямую через setupController, который тоже должен уйти.
                                                                    0
                                                                    Я нигде не видел информации об этом. Откуда вы это узнали? В доках модель создается именно так, как я указал. В референсе оба метода не помечены устаревшими.
                                                                      0
                                                                      Routable Components, которые никак не доедут, уберут понятие Controller, а с ним и доступ напрямую через model. Будет или attrs как в React, или что-то подобное

                                                                      https://github.com/ef4/rfcs/blob/routeable-components/active/0000-routeable-components.md
                                                                      https://gist.github.com/samselikoff/1d7300ce59d216fdaf97
                                                                        0
                                                                        Спасибо за ссылки. Это будет большой апдейт, когда компоненты наконец заменят контроллеры, но вряд ли написание роута станет менее элегантным или сложным. С нетерпением жду когда это случится, в конроллере не хватает хуков к run loop.
                                                                –1
                                                                Это красиво. Не спорю. Но лично у меня возникает комплекс неполноценности рядом с этим совершенством. Он сам все знает и умеет. А если у нас мнения с ним разойдутся, то что? Мне прогибаться под него или же искать варианты переопределения поведения? Когда вещь в себе — это может вылиться проблемами на моменте, когда мне нужно будет, чтобы она стала для меня.
                                                                  +1
                                                                  Мне поначалу было сложно понять как положить все сценарии на правильный Ember way, но постепенно все стало на свои места. Во первых это большой фреймворк, там есть много инструментов для разных нужд. Во вторых он гибкий. Он весьма легко расширяется.Минус в том, что нужно достаточно много времени что-бы выучить все что нужно.
                                                                  Для меня, основная причина почему мне понравился Эмбер, это то что он строг. Ничего магически работать не будет и вы не будете гадать, почему в какой то момент магия кончилась, и кто вообще за нее отвечал.
                                                                  Другой плюс, который я заметил спустя время, это что меня перестал бесить процесс написания интерфейсов. Проверка форм, отображение ошибок, анимаций загрузки и подобные вещи делаются легко и главное быстро.
                                                                    +1
                                                                    Спасибо за комментарий, за опыт.
                                                                    Сейчас я уже остановилась на одном стеке. И буду добивать его до финального конца. Но при случае я обязательно взгляну еще раз на ember.
                                                                0
                                                                Только не пинайте, я искренно хочу понять.
                                                                У меня может складывается неправильное представление, но настолько часто слышу на каждом углу о javascript-фреймворках, что кажется если писать классический веб-сайт, блог или интернет-магазин, то никак уже не обойтись без RESTful бекенда и к примеру Angular.

                                                                Вот есть проект. Есть php-разработчик, знающий, скажем, Symfony 2. Классические веб-сайты он может реализовать без хитромудрых javascript-фреймворков. А значит использовать меньше языков, тоньше стек технологий, иметь меньше вероятность словить баг, быть производительнее и выгоднее для бизнеса (меньше компетенций, за которые надо платить работнику).

                                                                Если вы не пишите подобие Gmail или в команде нет отдельного front-end разработчика, то зачем нужно себе усложнять жизнь?
                                                                  0
                                                                  Не нужно, вы правы. Если сервера достаточно, то можно все сделать на нем. Хотя сайт-аппликация создает меньше нагрузки на сервер, так как нужно передавать только данные, разметка уже есть на клиенте. Но если есть человек который хорошо работает с фреймворком на клиенте, то лучше делать на нем, так как если захочется потом добавить функционала или аппликацию то будет проще.
                                                                    0
                                                                    Я вижу смысл в случае, когда есть сразу два разработчика: для бекенда и фронтенда.
                                                                    Тогда мне, как бекенд-разработчику меньше работы, чтобы отдавать структурированные данные и не забивать себе голову клиентской частью.
                                                                    Либо в случае, когда приложение начинает всё больше походить на SPA и тогда серверный рендеринг становится действительно 5-м колесом.
                                                                    0
                                                                    Вы совершенно правы. Можно сделать без js, от слова совсем. И начиная делать проект я и пошла по этому пути. Но потом начался тот момент, что js нужен. Там где появляется интерактивность в дело вступал в js.
                                                                    На каком-то этапе мне захотелось, чтобы данные обновлялись без перезагрузки страницы. И снова был вариант прикручивать js скрипт. В какой-то момент я поняла, что количество сторонних разрозненных скриптов растет в прогрессии под мои хотелки, что отнимает время на внедрение, поддержку и сказывается на весе самой страницы. Поэтому пришла к фреймворку, который снимает часть вопросов.
                                                                    А так вы правы — можно обойтись без фреймворка.
                                                                      0
                                                                      Я тоже периодически спрашиваю себя: а не пора ли прикрутить js-фреймворк с шаблонизатором и роутингом? Проблема тут только в том, что не всегда понятен roadmap со стороны бизнеса и палить из пушки по воробьям не хотелось бы.
                                                                      С другой стороны, есть свой проект, как раз SPA, но делал через пень-колоду на голом jquery и requirejs. Надо бы перевести его на js-фреймворк. Наверное ваш опыт поможет сократить время :)
                                                                        0
                                                                        Ну если чем-то поможет, то это же будет здорово :)
                                                                        С проектами для бизнеса, с проектами по работе всегда проще (лично для меня было), потому, что у каждого своя зона ответственности, к работе приступаешь не стихийно, а с пониманием проекта. Потому, что пока выясняются у заказчика требования — многое становится на свои места. И выбор решений для реализации становится проще и более взвешенным.
                                                                        Со своим проектом для меня оказалось все иначе. Все наработанные годами практики на своем проекте не сработали :) Осознание того, что мне выбирать и я не ограничена в экспериментах никем, кроме как своим разумом и своей ответственностью сыграли злую шутку.
                                                                        Плюс отсутствие возможности посоветоваться и отсутствие здравой критики со стороны затянули в процесс изучения и поиска "совершенства".
                                                                        Поэтому я все таки здраво скажу, что надо или не надо и что надо — выбирайте соответственно целям, задачам, ресурсам.
                                                                        Но учитывайте, что выбор может стать опасной ловушкой :) Этот мой опыт тоже учтите ;)
                                                                      0
                                                                      Что вы будете делать когда к вашему проекту потребуется мобильное приложение?
                                                                        0
                                                                        В моей практике ни разу не было потребности для сайта еще делать мобильное приложение.
                                                                        Достаточно было использовать адаптивную верстку.
                                                                          0
                                                                          Ну значит у вас выборка не репрезентативна. Есть целая масса юзкейсов, которые нельзя покрыть просто сайтом. Начиная от вопросов безопасности (как хранить данные на клиенте безопасно), заканчивая вопросами производительности и UX.
                                                                            0
                                                                            Я делал API для мобильных приложений. Но они решали задачи, слабо пересекающиеся с сайтом.
                                                                              0
                                                                              Я последние 5 лет занимаюсь разработкой web-сервисов для мобильных приложенек. И где-то половину приложенек можно было бы сделать как web-приложения с точки зрения выполняемых функций, но того же UX добиться в web практически нереально.
                                                                      +1
                                                                      Впечатляет. Огромное спасибо. Если не программист, без высшего образования, девушка, блондинка одолела angular за 13 часов, то и я могу, должен, а то боялся.
                                                                      И вопрос — теперь, когда вы справились, это было нужно? Vanilla JS не хватило бы?
                                                                        0
                                                                        Не за что.
                                                                        Да, я действительно не программист. Да, без высшего образования. Да, даже скажу, что в том возрасте, когда мозг должен начинать отказываться воспринимать все новое и больше следовать шаблонам.
                                                                        В общем самый клинический случай из всех возможных на просторах хабра :)
                                                                        На фоне этого я считаю, что вам уже просто стыдно бояться не справиться ;)

                                                                        Отвечая на ваш вопрос отвечу так: нужно было. Потому, что js меня вообще пугал. Я не знаю как это объяснить, но для меня это был катастрофически-беспролазный лес. Я за несколько лет несколько раз открывала книжки, пыталась делать, но закрывала и бросала. Angular лично для меня стал отправной точкой. Чтобы на нем делать js надо понимать, надо понимать DOM, надо понимать сам ангуляр. Но с изучением ангуляр я перестала бояться самого js. Вот как-то так странно у меня произошло. Angular для меня дал возможность сделать, увидеть, что не работает, посмотреть все ошибки, понять, что проблема во мне и я уже без страха открывала мануалы по js, потому, что уже на практике видела то, что до сих пор пыталась изучить в теории и на практике вижу что для чего нужно. Т.е. у меня получился вот такой путь от обратного. Хватило бы или нет — не знаю, не могу сказать. Так как без этих экспериментов я скорее отказалась бы от идеи как таковой, чем пересилила бы сама себя.
                                                                        Но, это мой опыт, это такой мозг у блондинки. Вот такая женская логика :)
                                                                        +1
                                                                        Laracasts как источник обучения весьма грустен. Тейлор там рассматривает все достаточно поверхностно, перескакивая с одного на другое и совершенно не углубляясь. Все по верхам.

                                                                        Тейлор там уроки не ведет ) На Laracasts уроки от Jeffrey Way. А суждение о качестве сделаны по по бесплатным урокам?
                                                                          0
                                                                          Ок, Jeffrey. Простите мне мою ошибку.
                                                                          На чем основано суждение:

                                                                          отвечу так

                                                                            0
                                                                            Тогда вы должны были смотреть и курсы для "продвинутых", там уж точно не "по верхам" рассмотрено.
                                                                              0
                                                                              Попробую объяснить, что же я имела ввиду. Как точка входа в базовые вещи, которые описаны в документации достаточно неплохи.
                                                                              Но из раза в раз я наблюдала одну и ту же картинку — у Джеффри нет определенной структуры. Да, он пытается делать уроки с нуля до какого-то функционала (начиная с 4 версии лары у него уже было 3 или 4 серии таких попыток), но на каком-то моменте все это стопорится. Он долго разжевывает какой-то один момент, а в остальных он пробегает по верхам. И, словно ему становится скучно — он переключается на другое. В итоге курсов много (да даже по настройке редакторов банально — был storm, потом sublime, недавно vim). Редкие продвинутые курсы устаревают достаточно быстро. И они оторваны от базовых. Т.е. сложить поэтапную картинку в голове трудно.
                                                                              Но это исключительно мое имхо, мое впечатление, мои суждения.
                                                                                0
                                                                                Теперь понимаю.Благодарю за развернутый ответ.
                                                                                Планируете продлевать подписку на уроки?
                                                                                  0
                                                                                  В ближайшее время нет. После некоторой борьбы с роутингом лары и недостижением нужного результата решилась глубже погрузиться в js, включая и его серверную реализацию :)
                                                                                  Так, что сейчас изучаю вопросы о которых раньше думать даже не приходилось :)
                                                                                    0
                                                                                    некоторой борьбы с роутингом лары и недостижением нужного результата

                                                                                    А что не так с symfony/routing?

                                                                                    Так, что сейчас изучаю вопросы о которых раньше думать даже не приходилось :)

                                                                                    Например?
                                                                                      0
                                                                                      Не скажу точно — это проблема symfony или это такая реализация в laravel, не спец, чтобы однозначно ответить, но проблема в том, что генерировать те пути, которые мне нужны и так как мне нужно. У меня голова уже переключена, но пример сходу такой( за правильность синтаксиса не ручаюсь). В laravel путь вида http://domen.ru/catalog/category/{name}/subcategory{id} невозможен. Потому что или везде должно быть name или везде id. При попытке скрестить бульдога с носорогом я была повержена. А мне это нужно, чтобы при запросе от фронтэнда ссылки генерировались на api именно так, а не так как хочет laravel.
                                                                                      На счет вопросов о которых даже не думала — это касается серверной реализации. Самый банальный по моим прикидкам — sql инъекции и как от них защищаться :)
                                                                                        +1
                                                                                        Потому что или везде должно быть name или везде id.

                                                                                        Мы можем ввести три маршрута на один экшен контроллера и все будет хорошо.
                                                                                        Самый банальный по моим прикидкам — sql инъекции и как от них защищаться :)

                                                                                        prepared statements, и это не зависит от языка программирования.
                                                                                          0
                                                                                          Мы можем ввести три маршрута на один экшен контроллера и все будет хорошо.

                                                                                          Чисто теоретически я понимаю, что можно поколдовать с этой стороны, но чисто практически это умнее меня. :)
                                                                                          Для меня оказалось проще пойти по пути полного погружения в js и изобретения собственного "велосипеда" с блэкджеком и…
                                                                                          Вообще чем дальше, тем интереснее становится разбираться самостоятельно в первопричинах, а не в последствиях в виде framework'ов.
                                                                                          prepared statements, и это не зависит от языка программирования.

                                                                                          prepared statements — вот спасибо за наводку. Как раз ночью и натыкалась на старую статью на хабре о инъекциях и о том, как оно происходит, но на статью, которая была написана по следам о prepared statements — не наткнулась. Сейчас почитала — поняла в какую сторону смотреть.
                                                                                            0
                                                                                            Для меня оказалось проще пойти по пути полного погружения в js и изобретения собственного «велосипеда» с блэкджеком и…

                                                                                            Я в этом вижу одну из проблем разработчиков. Велосипедостраение и кастылеподпирание. Вообще мне кажется немного неправильным что у вас изначально возникла такая задача, так как это чуть-чуть так не правильно с точки зрения проектирования API. Ну да ладно. Это мне со стороны чувака, который последние лет 5 только апишки пишет так кажется.
                                                                                            prepared statements — вот спасибо за наводку

                                                                                            Всегда пожалуйста)
                                                                                              0
                                                                                              Я в этом вижу одну из проблем разработчиков. Велосипедостраение и кастылеподпирание.

                                                                                              Мир штука несовершенная.
                                                                                              А, если серьезно, то я пока не видела ни одного места, где бы жестко следовали бы определенным паттернам, заданным каким-то framework. Все равно где-то будут костыли, доводящие до ума существующее или делающие что-то свое и как захочется, а не как задумано "создателем". И, с одной стороны — это хорошо, с другой стороны — плохо. Хорошо тем, что развитие не останавливается, плохо в перспективе тем, что дела кому-то потом передавать, а передавать надо порядок, а не бардак. По мне любое мероприятие (framework я так же назову — мероприятием), где задействовано людей больше, чем один — уже будут появляться костыли и велосипедостроение. Это как в многоквартирном доме — убеди соседей, что нельзя хранить велосипеды там, где им не место. Кто-то послушает, а кто-то будет делать по своему и надзорные органы ему не указ, а так же законы и иже с ним. И бороться с этим бардаком можно или переехав в свой собственный дом, если что-то не устраивает, а в идеале — на необитаемый остров и строй с нуля свою электросеть, очистные сооружения и т.д.
                                                                                              Но это уже оффтоп, сорри, если что :)
                                                                                                0
                                                                                                где бы жестко следовали бы определенным паттернам

                                                                                                Это еще одна проблема — слепое следование "негласным правилам" и отсутствие рационального зерна. Вот есть например принцип — protected variations. Если просто — работает не трогай. Баги появляются тогда, когда разработчики что-то меняют. Потому вместо того что бы что-то поменять по возможности надо добавлять новое. А стало быть и код писать надо так, что бы можно было это делать. Защита кода от изменений.
                                                                                                А уже из этого принципа появляются низкая связанность, высокое зацепление, принцип единой ответственности, информационный эксперт. А из этих принципов все остальные паттерны.
                                                                                                Короче да, это оффтоп)
                                                                                                задействовано людей больше, чем один — уже будут появляться костыли и велосипедостроение.

                                                                                                TDD и код ревью спасут мир.
                                                                                                  0
                                                                                                  TDD и код ревью спасут мир.

                                                                                                  Сколько работала, независимо от размера компании, TDD и ревью со стороны людей, принимающих решения в бизнесе — это считалось нерациональной тратой ресурсов.
                                                                                                  Я понимаю почему так происходит, и сейчас начинаю понимать почему это плохая практика :)
                                                                                                    0
                                                                                                    Я понимаю почему так происходит, и сейчас начинаю понимать почему это плохая практика :)

                                                                                                    Что именно? Tdd и код ревью? На самом деле проблема с TDD обычно в том, что люди тесты писать не умеют. Ну то есть… вот совсем. Обычно разработчики начинают писать тесты для своего не тестируемого кода, завязываются на реализации, и в итоге поддерживать такие тесты становится дорого. А потом начинается "TDD только хуже делает", ну так что поделать если люди не умеют им пользоваться.
                                                                                                    Ну а код ревью — это обычно занимает 10 минут в день.
                                                                                                    Что до людей принимающих решение в бизнесе — tdd и т.д. это практики, о которых бизнесу знать не нужно. Если это бизнесу профита не приносит — значит оно нам не надо. Но в большинстве случаев правильное TDD снижает риски и в долгосрочной перспективе стоимость поддержки и разработки.
                                                                                                      0
                                                                                                      Под плохой практикой я подразумевала отсутствие как минимум код-ревью.
                                                                                                      Про tdd — тут не могу ничего сказать, так как теоритически знаю, практически даже не пыталась.
                                                                                                      А на счет 10 мин занимает ревью — хм…
                                                                                                      Это смотря как организована работа. Но вот критиковать эти дебри я не буду. По работе мне не приходилось об этом думать. Я могла видеть только результат и то не в виде исходников кода, а в виде готового работающего продукта.
                                                                                                0
                                                                                                Всё же лучше использовать QueryBuilder или что-то более высокоуровневое. Сырой SQL быстро разрастаяется до неподдерживаемого состояния.
                                                                                                  0
                                                                                                  А внутри query builder-а у нас что? prepared statements. Что до разрастания сырого sql, table data gateway, row data gateway не дураки придумали. Хотя data mapper в большинстве случаев лучше.

                                                                                                    0
                                                                                                    А внутри query builder-а у нас что? prepared statements.
                                                                                                    На самом деле нет. И совершенно не важно, что у него внутри.

                                                                                                    row data gateway не дураки придумали. Хотя data mapper в большинстве случаев лучше.
                                                                                                    Это и есть «что-то более высокоуровневое».
                                                                            0
                                                                            Не знаю какой там у Вас опыт, но хороший вкус, судя по коду, явно присутствует, а этим не каждый программист с большим стажем похвастаться может. Спасибо за статью и за милые картинки))
                                                                              0
                                                                              Спасибо за комплимент комментарий.
                                                                              А как оценивается наличие/отсутствие вкуса по коду?
                                                                              Мне всегда казалось, что любые данные с которыми имеешь дело должны быть просто структурированы, и сходу понятны. Или я не о том думаю?
                                                                                +1
                                                                                Даже не знаю как ответить. Нужно самому много раз учавствовать в код ревью чтобы начать чувствовать как написан очередной документ. Даже на хабре часто встречаются листинги с "магическими строками" и объявление переменных посреди логики. У вас я вижу четкую структуру. Каждая сущность оформлена в едином стиле, это, на самом деле, удивляет с учетом упомянутого "чукча не программист". Я последнее время часто занимаюсь ревью кода, который потом отправляется в мастер и в большинстве случаев приходится оставлять комментарии по исправлению стилистических ошибок не смотря на наличие код стайла. У Вас я не нашел к чему придраться, есть некоторые моменты которые я бы сделал по другому, но это. опять же. дело вкуса.
                                                                                  +1
                                                                                  Ну тут не моя заслуга, а вытекающие последствия из:
                                                                                  1. просмотра исходников на github в попытках осилить некоторые туториалы. Очень часто мне хотелось плакать, потому, что насколько можно написать хаотично — настолько часто пишут хаотично. В общем складывается внутреннее ощущение — как я не хочу делать.
                                                                                  2. профессиональная деформация. Что написание планов, что составление требований для программистов, что описание маркетинговых стратегий, проведение исследований и описание выводов из них — требуют структуры. Всегда приходилось помнить о том, что это будут читать и воспринимать непоследовательно, а потому из любой части документа всегда надо быстро сказать в какую часть документа по этому вопросу смотреть :) Я этому очень долго училась. И сейчас до сих пор осталась привычка начинать с черновика и делать по несколько ревизий, прежде чем нарисуется окончательная чистая структура.
                                                                                    Да и коллеги-программисты меня как менеджера часто мучили вопросами а где-а что в документе, чем приучили раскладывать по полочкам и тратить время только на то, чтобы обсудить и доописать моменты спорные в функционале.
                                                                                    Так, что это не вкус, это скорее опыт, взятый из других областей и перенесенный в новую для себя область.
                                                                                    +1
                                                                                    Ну вот. Сами себя скомпроментировали)
                                                                                    А вообще, одно дело структура и порядок, а другое дело когда читаешь код и видишь мысль, весь путь ее развития, и как одна эта мысль пронизывает все листинги. Может и правда, опыт и порядок сделали свое дело, но это не отменяет того что код приятно читать. Удачи Вам в новой для Вас сфере)
                                                                                      0
                                                                                      Спасибо :)
                                                                              0
                                                                              Спасибо за статью, за грамотно и подробно преподнесенную информацию, скриншоты.
                                                                              Сейчас разрабатываю бекэнд на PHP и фронтэнд на Angular 2 (5) — иду практически тем же путем, что и описанный в статье. Осознание того, что кто-то уже прошел подобным путем — помогает и поддерживает.

                                                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                              Самое читаемое