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

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

Для остальных: у меня за плечам незаконченный лет 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. За орфографию, грамматику, стилистику, некоторую саркастичность заранее прошу прощения, а при указании на что-то из первых трех пунктов — исправлю это :)

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

И огромное вам спасибо, если дочитали этот пост!

Комментарии (121)


  1. rroyter
    04.03.2016 02:38
    +1

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


    1. 4ertovo4ka
      04.03.2016 02:51
      +3

      А можно с этого момента поподробнее, для общего развития: пример того, что хотели сделать?


      1. rroyter
        04.03.2016 08:06
        -3

        Ну вот например написать в шаблоне

        {{(function(a){console.log(a);})(3)}}
        не получится.


        1. DigitalSmile
          04.03.2016 10:45
          +5

          И зачем Вам такое писать в шаблоне, если не секрет?


          1. Akuma
            04.03.2016 10:58
            -4

            Иногда так бывает удобно делать, когда функционала очень мало и выносить его в отдельный файл просто бессмысленно.


            1. DigitalSmile
              04.03.2016 11:10
              +4

              Имхо, шаблоны должны оставаться по максимуму "чистыми" от логики. Хочется если что-то мелкое написать, можно это сделать через компонент (контроллер в Angular 1.x). Я не вижу проблемы, почему надо добавлять или менять сложившееся поведение.


              1. Akuma
                04.03.2016 11:15
                -2

                В реальной жизни оставлять шаблоны чистыми не получится. Логика все равно будет, если у вас что-то серьезнее Hello World.

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

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

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


                1. DigitalSmile
                  04.03.2016 11:28
                  +2

                  В реальной жизни оставлять шаблоны чистыми не получится. Логика все равно будет, если у вас что-то серьезнее Hello World.

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

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

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

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

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

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


                  1. Akuma
                    04.03.2016 11:34

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

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

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

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


                    1. DigitalSmile
                      04.03.2016 11:45

                      Имею ввиду все эти ng-директивы: циклы, условия и пр.

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

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

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


                      1. Akuma
                        04.03.2016 11:54

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

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


                        1. DigitalSmile
                          04.03.2016 12:13

                          Вообще так и делал, но показалось не слишком удобно, особенно когда нужно не просто разделить данные, а реагировать на их изменение.

                          С реакцией на изменения будет чуть сложнее. Тут надо определится кто инициатор изменений и где и как их надо ловить. Из этого и строить этот интерфейс. Но в целом, тоже не так уж и сложно. И кстати, можно вполне обойтись без коллбеков. В директивах есть $watch (он как раз тут подойдет), в котором будут вызываться методы интерфейса для передачи значения в интересующий модуль.


                          1. Akuma
                            04.03.2016 12:16

                            При таких проверках большой проект будет очень медленно работать. Желательно чтобы директива не каждый раз вызывала factory.getSomeData() при изменении $scope, а более точечно. Хотя на ангуляре такое вряд ли получится.
                            Ну да ладно, у него много и плюсов )


                    1. Fesor
                      04.03.2016 14:18

                      А зачем вам "связывать" компоненты, расположенные на одном уровне?

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


                      1. Akuma
                        04.03.2016 14:21

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


                        1. Fesor
                          04.03.2016 14:56

                          А если на самом нижнем уровне я нажал кнопку и нужно изменить данные, у вас что происходит?

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

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

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


                          1. LastDragon
                            04.03.2016 15:27

                            ну и "ивенты" ангуляра — это ивенты ангуляра, нечего нам их самим слать

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

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

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


                            1. Fesor
                              04.03.2016 16:26

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

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

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

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

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


                              1. LastDragon
                                04.03.2016 17:00

                                Система ивентов в ангуляре

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

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

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


                                1. Fesor
                                  04.03.2016 20:01

                                  что без деструкторов в js совсем печально

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

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

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

                                  Короче я могу сказать только одно — просто не используйте $scope. Вообще. И тогда жить с ангуляром становится в разы приятнее.


                  1. rroyter
                    04.03.2016 21:54

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

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


                    1. Fesor
                      04.03.2016 21:58

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

                      А зачем так в принципе делать? Вот серьезно?


                      1. rroyter
                        04.03.2016 22:11

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

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

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


          1. rroyter
            04.03.2016 21:51

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

            Например у меня есть массив аккаунтов, и мне надо достать баланс по id. В шаблоне можно написать

            m.accounts[#i].balance
            

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


            можно конечно вынести поиск в модель, но это не всегда удобно, и иногда вообще невозможно (когда шаблон собирается из кусочков на сервере).


            1. Fesor
              04.03.2016 21:59
              +1

              Если вам надо сделать поиск по ID то вы должны его делать не в шаблонах а в контроллере. И у меня нет ни одного кейса при котором это нельзя сделать или по каким-то неведомым причинам это неудобно.


              1. rroyter
                04.03.2016 22:05

                У нас шаблон собирается на сервере из конфигурации. Хотим уменьшить количество мест где надо править код. Для этого было бы очень удобно вставлять небольшие инлайновые функции. А так получается, что сегодня нам надо искать по id, а для этого надо менять и webapi контроллер который выдает шаблоны, и ангуляр контроллер который байндится на клиенте. Завтра надо будет искать не по id, а по чему нибудь ещё, и опять менять код в нескольких местах.


                1. Fesor
                  04.03.2016 22:51

                  Хотим уменьшить количество мест где надо править код.

                  Для этого можно было бы сделать простой RPC на сервере, работающий с данными, и формы вынести целиком и полностью на клиент. Тогда все было бы просто, удобно, и не нужно было бы плодить эти дикие кастыли.


                  1. rroyter
                    04.03.2016 23:18

                    Тогда не получим автоматическую серверную валидацию, и все равно код плодить придется.


                    1. Fesor
                      05.03.2016 16:54

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

                      А логика в темплейтах — это автоматический проигрыш и вообще становится непонятно зачем брать ангуляр для этого.


                      1. rroyter
                        05.03.2016 17:31

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


                        1. Fesor
                          05.03.2016 17:41

                          но не жизнеспособно в боевых условиях.

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

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

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

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


        1. Delias
          05.03.2016 13:53

          Ну вот, типичный пример блондинки.


    1. AMar4enko
      04.03.2016 06:42
      +6

      Потому что шаблоны в ангуляре декларативные.


      1. rroyter
        04.03.2016 08:08

        Ну на самом деле они там делают лексический анализ, строят AST тэгов. Могли бы и добавить поддержку javascript кода, тем более что они уже сделали ограниченную поддержку некоторых ключевых слов, например "if", "else".


        1. AMar4enko
          04.03.2016 08:36
          -2

          Какая у вас основная специфика работы? Frontend / backend? Как долго вы с Ангуляром знакомы? Судя по вашим эмоциям относительно Ангуляр 2 вы с первым не работали.


          1. rroyter
            04.03.2016 08:45
            +2

            Каким таким эмоциям?


    1. Ohar
      04.03.2016 12:06
      +5

      инлайновые функции в темплейтах

      Да вас святой водой окропить надо.


    1. tamtakoe
      04.03.2016 13:56
      +2

      А еще он кофе не умеет готовить и посуду мыть. Нафиг такая недоделка нужна кому-то...


      1. DigitalSmile
        04.03.2016 14:16
        +3

        Извиняюсь за оффтоп, но не могу не спросить. Ваша замечательная библиотека https://github.com/tamtakoe/oi.select планирует дальше развиваться? Мы ее используем в своих проектах, но хотелось бы решение некоторых тикетов. И кстати спасибо за труд :)


        1. tamtakoe
          06.03.2016 18:16

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


  1. kafeman
    04.03.2016 03:46
    +7

    Мне кажется, вся проблема в том, что вы решили изучить Angular 2 для того, чтобы изучить Angular 2. При этом у вас в голове есть какие-то свои задачи, свои требования, свой подход, и все это очень сильно отличается от того, что предлагает фреймворк.

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

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

    P.S. Стиль статьи напомнил мне материалы на Django Girls :-)


    1. 4ertovo4ka
      04.03.2016 04:37
      +3

      P.S. Не читала, не знаю, открывать не буду :)

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

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

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


      1. kafeman
        04.03.2016 05:04

        В таком случае, я неверно интерпретировал ваше отношение к фреймворку.

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

        Для такой задачи я бы из списка выбрал Backbone или первый Angular. Но если вы действительно копались в React, то философию, наверное, поняли.


        1. 4ertovo4ka
          04.03.2016 06:41

          Первый Angular медленно но верно подводят сейчас ко второму. 1.5 если посмотреть — туда уже и частично роутинг пытаются впихнуть улучшенный и ведут по написанию к стилю angular2.
          Но не срослось у меня с ним, так как для моего понимания — двойка более структурированная. Мне в ней проще ориентироваться, потому, что для меня она легко читается и я мало времени трачу на то, чтобы понять откуда и куда растут ноги.
          C backbone то же самое, что и с react — для меня это оказалось сложной задачей — вмешивать разметку в срипт.
          Такая методика у меня стойко ассоциировалась с женской логикой — она есть, но понять ее невозможно.
          Я уже в течении трех месяцев провожу эксперименты. Я долго решала на чем делать бэкенд, с прицелом на будущее. И изоморфный meteor пощупала. Не понравилось, что там mongo. Хотя они сейчас и собираются внедрять graphql, но это тоже все еще неясно и непонятно как будет работать. Помучила Spring. Он чудесен с моей точки зрения, но активное внедрение множества компонентов, которые дублируют друг друга — это ад. Плюс не все четко отлажено, и у меня начали вылезать баги с передачей-получением запросов. То кодировка шалила, то еще что-то.
          В плане api под backend был интересен sailsjs. Но, к сожалению у него достаточно неповоротливые разработчики и некоторые баги они очень долго не фиксят. Плюс одна единственная книжка по этому фреймворку и не очень понятная для меня документация свели на нет мой интерес.
          И это то, что я сейчас вспомню, что я тестила все по той же схеме :)
          Так как воспитывалась я преимущественно папой и в квартире, которая больше напоминала сервисный центр, чем квартиру, то перебрать варианты, попробовать, поменять местами, снова попробовать, разобрать, собрать, включить, потом поискать еще более оптимальный вариант решения — это мой вариант поиска решений. И, когда я писала статью я правда пыталась показать, что простая задачка из простой, но реальной жизни может быть решена достаточно быстро. а при условии отсутствия навыков я считаю, что это вообще спринтерский забег.


          1. Imbolc
            04.03.2016 11:55

            Для бэкенда, если js смотреть хороши koa.js — там нормальная асинхронность через async / await. И loopback — там обычные rest api описывается просто декларативно. В плане фронтенда интересен react native, раз вы и так по краю ходите, легко будет портировать проект на мобильники.


            1. 4ertovo4ka
              04.03.2016 12:22

              koa смотрела уже под занавес всех экспериментов. Каюсь, но запала в нее вникать уже не хватило.
              Loopback тоже смотрела. Не помню что меня в нем остановило. Что-то точно было. Может не то место и время, может мало примеров, может быть отсутствие чего-то нужного. Я к нему 3 раза пыталась подступиться. Не нашли взаимности. А потому с бэкенд пошла по пути наименьшего сопротивления в итоге.
              ReactNative не смотрела. По краю я уже завязала ходить. Я уже доя себя остановилась на определенном стэке, так, что дальше тут в глубину буду копать.


              1. Imbolc
                04.03.2016 12:27

                Если в плане обучения — то лучше всего loopback, он вас хорошим паттернам научит. Там уже есть вся структура api, правильная иерархия url и т.п. Вам этого нехватает.


                1. 4ertovo4ka
                  04.03.2016 22:12

                  Не буду спорить про иерархию. С этим есть проблема :)
                  Я уже чувствую, что что-то идет не так. Но пока не могу сформулировать, что именно.
                  Чтение литературы по REST и как оно должно быть у меня почему-то оставляло привкус того, что это не очень удобно, не совсем вписывается в мое понимание "идеального" мира.
                  Я пока экспериментирую как оно должно быть с моей точки зрения. Думаю, что через какое-то количество времени приду к некоторому пересмотру.


      1. elimoon
        09.03.2016 03:17

        Во-первых, спасибо за статью.

        Поделюсь своим опытом 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.


    1. 4ertovo4ka
      04.03.2016 05:02
      +3

      P.S. Почитала, но стремилась все таки, чтобы больше напоминало это:

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


  1. sayber
    04.03.2016 04:34
    +3

    Люблю такое изложение информации подкрепленной кодом / примерами.
    Легко и интересно читать.


    1. 4ertovo4ka
      04.03.2016 04:39
      +7

      Боже, спасибо вам за бальзам на мое сердце!
      Не знаю как у других, но я искренне боялась писать на хабр.
      Коленки до сих пор дрожат :)


  1. 4ertovo4ka
    04.03.2016 04:54

    И заранее приношу извинения всем, кому мне так хотелось бы поставить плюсик в комментарий — я не успеваю поймать тот момент, когда моя карма это позволяет :)


  1. Demetros
    04.03.2016 06:27

    Странный у вас профиль — приглашена более чем на полгода позже, чем зарегистрирована. У меня, например, логично — сначала приглашен, через полчаса зарегистрирован.


    1. 4ertovo4ka
      04.03.2016 06:44

      Не обращала на это внимания. Удивительный сбой, потому, что я прекрасно помню время, место и какие дела я отложила, когда мне пришло приглашение. И было это в 2012 году :)


    1. Nartis
      04.03.2016 07:03
      +2

      А что странного? Я приглашен через полтора года после регистрации, как написал в песочницу, так и приглашен, а до этого ридонли.


      1. 4ertovo4ka
        04.03.2016 07:05

        Ну я и не регистрировалась и не писала до того момента, как меня пригласили. Так, что в моем случае это правда странно.


        1. Nartis
          04.03.2016 07:10

          Тогда извиняюсь:)


          1. 4ertovo4ka
            04.03.2016 07:21
            +1

            Да тут не за что :)
            Но вообще интересно. Почему-то в моей голове до сих пор есть убеждение, что зарегистрироваться можно было только имея инвайт.
            А вы вот сейчас мне обратное показали.
            Теперь вот вместо сна буду думать почему же я думала неправильно :)


            1. heathen
              04.03.2016 17:13
              +1

              В то время, когда вы регистрировались, не было read-only регистрации. Так что да, только по инвайтам: личным или через песочницу. Хотя, вы уже и так либо выспались, либо не выспались, я думаю. :)


              1. 4ertovo4ka
                04.03.2016 20:46
                +1

                До сих пор второе :)
                Ладно, значит хабр продолжил традицию — на мне вылезают везде баги :)
                И понимайте как хотите ))))
                Сорри за оффтоп


  1. mr47
    04.03.2016 08:36
    +1

    Очень многие кто полюбили Angular 1.x не могут спокойно перейти на 2.x что очень и очень странно. Кто то кричит что 2ка — ужасна. Кто то что нет нужно. А там временем — http://thenewstack.io/google-preps-angular-2-final-release/


    1. Imbolc
      04.03.2016 09:14

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

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


      1. DigitalSmile
        04.03.2016 10:51

        Двусторонее связывание проще и удобнее, односторонее «правильнее» и может давать преимущество в сложных проектах.

        А можете какие-то аргументы привести? Просто интересно, чем это one-way связывание правильнее two-way?


        1. Imbolc
          04.03.2016 11:09

          А посмотрите просто историю как фейсбук придумали реакт. Насколько я помню, у них там какой-то рассинхрон в юай был. Одностороннее связывание решило эту проблему.


          1. DigitalSmile
            04.03.2016 11:17

            В таком случае, это не из разряда "правильное/не правильное". Смена подхода просто помогла решить проблему фейсбука в своем фреймворке, вот и все.
            Вопрос не праздный я задавал. Мне тут с пеной у рта доказывали, что one-way биндинг это костыль, чтобы ангуляр работал быстрее. Теперь вот оказывается, что one-way биндинг это "правильно"… Во всех этих спорах я не вижу ни одного аргумента, который смог бы принять, к сожалению.


            1. Imbolc
              04.03.2016 11:36

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

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

              Меня лично это проблема не беспокоит, т.к. ничего такого сложно-связанного нету. Но если бы было, я бы задумался об one-way-flow.


              1. DigitalSmile
                04.03.2016 11:51

                Костыль для скорости — это 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-стратегии).


                1. Imbolc
                  04.03.2016 11:59

                  Разница в том, что one-time binding не предполагает последующего изменения отрендеренного хтмл, а one-way предполагает.


                1. Imbolc
                  04.03.2016 12:03

                  она решается достаточно просто

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


              1. LastDragon
                04.03.2016 12:33

                И вот эти элементы и сервер одновременно её меняют, как это разрулить?

                В js "одновременно" невозможно в принципе — он однопоточный по своей природе...


                1. Imbolc
                  04.03.2016 12:35

                  Вы не поняли о чём речь или находите слово недостаточно корректным?


                  1. LastDragon
                    04.03.2016 12:50

                    Да, оно некорректно, кроме того вам в любом случае придется решать чье значение более приоритетно — то что пришло с сервера или то что изменилось локально.


                    1. Imbolc
                      04.03.2016 12:54

                      Вот о том и речь, что с двусторонним связыванием у вас нету возможности это решать. У вас есть только переменная во вью-модел, которая может спонтанно измениться из нескольких источников.


              1. vintage
                04.03.2016 18:31

                Давайте я вам расскажу про правильный two-way биндинг.

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

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

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

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

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

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

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


            1. mr47
              04.03.2016 11:44

              По тестым коих великое множество, что react что angular не самые быстрые решения. Очень хорошие результаты показывает backbone + incremental dom.

              (Результаты можете погуглить или посмотреть что делал jridgewell )


              1. mr47
                04.03.2016 11:50

                ссылочка на демо http://jsfiddle.net/fwdna26c/3/


                1. DigitalSmile
                  04.03.2016 11:53

                  Спасибо, поглядим.


      1. baka_cirno
        04.03.2016 12:51

        А почему кто-то должен переходить с Angular 1.x на Angular 2? Это совершенно разные фреймворки, у которых общей кодовой базы почти нет, если не считать бекпортированного роутера и нескольких фич в 1.5. С таким же успехом можно переходить на React или Ember.


    1. dshster
      04.03.2016 14:37

      У меня сейчас такая ситуация — год разрабатывал на Angular 1.* и нужно бы куда-то переходить: либо Angular2, либо React. Я понимаю, что Angular2 связан с Angular1 только названием, но пугает не это, а отсутствие инфраструктуры — пока рожался Angular2 все кто мог ушли на React и основали там довольно внушительное сообщество. Поэтому переходя сейчас на Angular2 есть риск остаться белой вороной, если ты, конечно не работаешь в Microsoft — они могут позволить себе создать сообщество вокруг чего угодно.


      1. aikixd
        04.03.2016 14:40
        +1

        Берите Эмбер. Я ниже привел пример кода на нем, смотрите как красиво.


  1. Imbolc
    04.03.2016 08:57

    А чем описанная задача сложнее todo-листа не пойму?

    Вообще, ожидал увидеть некоторую кривую вхождения. Проблема же (с первым ангуляром, допустим) была не в том, что сложно освоить азы. Сложности начинались дальше. Грубо говоря, кривая вхождения была экспоненциальной — чем дальше тем сложнее.


    1. 4ertovo4ka
      04.03.2016 12:06

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


      1. Imbolc
        04.03.2016 12:11

        helloWorld — это же не todo-list. А последний это как раз и есть то, что вы описываете в статье — простенькое взаимодействие с сервером. Совершенно на любом фреймворке это будет выглядеть просто. Случай очень простой. Разница между фреймворками проявится при усложнении системы.

        Вот тут умный человек очень хорошо рассказал зачем все эти рекаты и вторые ангуляры нужны, очень рекомендую, тут именно суть, а не свистелки: https://www.youtube.com/watch?v=DCeNCr2tKOI


        1. 4ertovo4ka
          04.03.2016 12:15
          +2

          Я воздержусь от холиваров на тему удачности-неудачности примера. Скажу так-для меня этот пример более информативен, чем todo для выбора инструмента.


          1. Imbolc
            04.03.2016 12:23
            +1

            При чём тут холивар? Разве я отстиваю какой-то другой пример? Я же вам привожу конкретные аргументы того, что функционал вашего примера — это подмножество функционала todo-листа.

            В todo есть: получение коллекции, создание элемента, изменение элемента, удаление элемента. У вас только первые два пункта.


  1. Mox
    04.03.2016 11:41
    +1

    А есть ли какие то принципы расположения файлов? А то не понятно почему модель лежит в папке dashboard


    1. 4ertovo4ka
      04.03.2016 12:11
      +1

      Есть. Так как это кусочек самого начала проекта, то dashboard будет включать в себя все, что будет относиться к работе админки. Поэтому да, выглядит странно со стороны сейчас. Я могу за выходные привести эти кусочки в порядок и отдельным моментом выложить на github, если есть интерес к этому.


  1. janson
    04.03.2016 12:29

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

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

    Простые вещи разжёвываются в документации, а в сложные отправляют "посмотреть код".


    1. LastDragon
      04.03.2016 12:41

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


    1. Akuma
      04.03.2016 12:47

      Я встречал хуже. Есть документация — копируешь код примера — не работает. Жмешь на LivePreview — работает.
      Оказалось, что код примера в документации и код в LivePreview чуть-чуть отличался. Только вот дойти до этого пришлось самому.


    1. 4ertovo4ka
      04.03.2016 19:10

      Не поняла немного. Документация. — что в данной статье документация?
      Я специально привела скрин структуры, так как не выложила исходники на гит. Исходники выложу. Структура останется та же. Если скопировать весь код отсюда в той же структуре что есть — оно будет работать. Так как это честная копия работающего кусочка.
      Скрин прикладывала именно из-за некоторого бардака в файлах. Вынужденный рабочий бардак.
      Исходники предлагаю выложить с приведенной впорядок структурой и под это уже поправить статью.
      Комментарии в коде лично для меня удобнее, чем листать по 100 экранов в поисках, где это описывали.
      А теперь — что в итоге улучшить? Как понятнее сделать? ))))


  1. HomoLuden
    04.03.2016 13:24

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

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

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

    У вас такая проблема возникла? Мне кажется вы зря решили опустить детали реализации серверной части.


    1. 4ertovo4ka
      04.03.2016 17:27

      Да, вы правы. Это проблема вылезла. Но решилась плагином laravel/cors.


  1. aikixd
    04.03.2016 14:14
    +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. gagoman
      04.03.2016 16:41
      +1

      На самом деле сейчас в Ember тот еще разброд и шатание (сам пишу на нем с 1.3).

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

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

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

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

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

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

      А так, куча вещей помечено deprecated, но при этом замены пока нет.


      1. aikixd
        04.03.2016 18:20

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

        Я сейчас сижу на 2.4бета у меня ни одного депрекейшена. Проект из 3 аппликаций и одного общего аддона.


        1. gagoman
          04.03.2016 19:13

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


          1. aikixd
            04.03.2016 19:52

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


            1. gagoman
              04.03.2016 20:03

              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


              1. aikixd
                04.03.2016 20:09

                Спасибо за ссылки. Это будет большой апдейт, когда компоненты наконец заменят контроллеры, но вряд ли написание роута станет менее элегантным или сложным. С нетерпением жду когда это случится, в конроллере не хватает хуков к run loop.


    1. 4ertovo4ka
      04.03.2016 19:03
      -1

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


      1. aikixd
        04.03.2016 20:05
        +1

        Мне поначалу было сложно понять как положить все сценарии на правильный Ember way, но постепенно все стало на свои места. Во первых это большой фреймворк, там есть много инструментов для разных нужд. Во вторых он гибкий. Он весьма легко расширяется.Минус в том, что нужно достаточно много времени что-бы выучить все что нужно.
        Для меня, основная причина почему мне понравился Эмбер, это то что он строг. Ничего магически работать не будет и вы не будете гадать, почему в какой то момент магия кончилась, и кто вообще за нее отвечал.
        Другой плюс, который я заметил спустя время, это что меня перестал бесить процесс написания интерфейсов. Проверка форм, отображение ошибок, анимаций загрузки и подобные вещи делаются легко и главное быстро.


        1. 4ertovo4ka
          04.03.2016 22:09
          +1

          Спасибо за комментарий, за опыт.
          Сейчас я уже остановилась на одном стеке. И буду добивать его до финального конца. Но при случае я обязательно взгляну еще раз на ember.


  1. akubintsev
    04.03.2016 17:22

    Только не пинайте, я искренно хочу понять.
    У меня может складывается неправильное представление, но настолько часто слышу на каждом углу о javascript-фреймворках, что кажется если писать классический веб-сайт, блог или интернет-магазин, то никак уже не обойтись без RESTful бекенда и к примеру Angular.

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

    Если вы не пишите подобие Gmail или в команде нет отдельного front-end разработчика, то зачем нужно себе усложнять жизнь?


    1. aikixd
      04.03.2016 18:31

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


      1. akubintsev
        04.03.2016 19:06

        Я вижу смысл в случае, когда есть сразу два разработчика: для бекенда и фронтенда.
        Тогда мне, как бекенд-разработчику меньше работы, чтобы отдавать структурированные данные и не забивать себе голову клиентской частью.
        Либо в случае, когда приложение начинает всё больше походить на SPA и тогда серверный рендеринг становится действительно 5-м колесом.


    1. 4ertovo4ka
      04.03.2016 19:00

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


      1. akubintsev
        04.03.2016 19:14

        Я тоже периодически спрашиваю себя: а не пора ли прикрутить js-фреймворк с шаблонизатором и роутингом? Проблема тут только в том, что не всегда понятен roadmap со стороны бизнеса и палить из пушки по воробьям не хотелось бы.
        С другой стороны, есть свой проект, как раз SPA, но делал через пень-колоду на голом jquery и requirejs. Надо бы перевести его на js-фреймворк. Наверное ваш опыт поможет сократить время :)


        1. 4ertovo4ka
          04.03.2016 20:56

          Ну если чем-то поможет, то это же будет здорово :)
          С проектами для бизнеса, с проектами по работе всегда проще (лично для меня было), потому, что у каждого своя зона ответственности, к работе приступаешь не стихийно, а с пониманием проекта. Потому, что пока выясняются у заказчика требования — многое становится на свои места. И выбор решений для реализации становится проще и более взвешенным.
          Со своим проектом для меня оказалось все иначе. Все наработанные годами практики на своем проекте не сработали :) Осознание того, что мне выбирать и я не ограничена в экспериментах никем, кроме как своим разумом и своей ответственностью сыграли злую шутку.
          Плюс отсутствие возможности посоветоваться и отсутствие здравой критики со стороны затянули в процесс изучения и поиска "совершенства".
          Поэтому я все таки здраво скажу, что надо или не надо и что надо — выбирайте соответственно целям, задачам, ресурсам.
          Но учитывайте, что выбор может стать опасной ловушкой :) Этот мой опыт тоже учтите ;)


    1. Maxxon
      04.03.2016 22:33

      Что вы будете делать когда к вашему проекту потребуется мобильное приложение?


      1. akubintsev
        07.03.2016 21:23

        В моей практике ни разу не было потребности для сайта еще делать мобильное приложение.
        Достаточно было использовать адаптивную верстку.


        1. Fesor
          07.03.2016 22:13

          Ну значит у вас выборка не репрезентативна. Есть целая масса юзкейсов, которые нельзя покрыть просто сайтом. Начиная от вопросов безопасности (как хранить данные на клиенте безопасно), заканчивая вопросами производительности и UX.


          1. akubintsev
            09.03.2016 17:46

            Я делал API для мобильных приложений. Но они решали задачи, слабо пересекающиеся с сайтом.


            1. Fesor
              09.03.2016 18:18

              Я последние 5 лет занимаюсь разработкой web-сервисов для мобильных приложенек. И где-то половину приложенек можно было бы сделать как web-приложения с точки зрения выполняемых функций, но того же UX добиться в web практически нереально.


  1. uvelichitel
    04.03.2016 21:40
    +1

    Впечатляет. Огромное спасибо. Если не программист, без высшего образования, девушка, блондинка одолела angular за 13 часов, то и я могу, должен, а то боялся.
    И вопрос — теперь, когда вы справились, это было нужно? Vanilla JS не хватило бы?


    1. 4ertovo4ka
      04.03.2016 22:07

      Не за что.
      Да, я действительно не программист. Да, без высшего образования. Да, даже скажу, что в том возрасте, когда мозг должен начинать отказываться воспринимать все новое и больше следовать шаблонам.
      В общем самый клинический случай из всех возможных на просторах хабра :)
      На фоне этого я считаю, что вам уже просто стыдно бояться не справиться ;)

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


  1. xelam
    06.03.2016 01:26
    +1

    Laracasts как источник обучения весьма грустен. Тейлор там рассматривает все достаточно поверхностно, перескакивая с одного на другое и совершенно не углубляясь. Все по верхам.

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


    1. 4ertovo4ka
      07.03.2016 03:26

      Ок, Jeffrey. Простите мне мою ошибку.
      На чем основано суждение:

      отвечу так


      1. xelam
        12.03.2016 18:23

        Тогда вы должны были смотреть и курсы для "продвинутых", там уж точно не "по верхам" рассмотрено.


  1. xskif
    12.03.2016 11:45

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