Алексей Золотых
twitter: @zolotyh
email: aazolotyh@gmail.com
Dart: Language updates, use cases, discussion with Google developers
https://goo.gl/1v9R1R<input type="text" ng-model="yourName" >
<h1>Hello {{yourName}}!</h1>
<input type="text">
<p>Hello</p>
<script>
$(function() {
var $input = $('input'),
$p = $('p'),
startValue = $p.text();
$input.on('keyup', function(){
$p.text(`${startValue} ${$input.val()}`)
})
});
</script>
— Чудо?
— Безусловно!
— За все нужно платить!
Думаете проблема только в производительности!?
import Workout from "../../Components/WorkoutComponent/WorkoutComponent";
import Token from "../../getCSRFToken";
import animation from "css-animation";
class WorkoutContainer extends React.Component {
constructor() {
super();
this.handleDeletingWorkoutItem = this.handleDeletingWorkoutItem.bind(this);
this.toggleItemFullData = this.toggleItemFullData.bind(this);
this.state = {
workoutName: "",
workoutData: []
};
}
componentWillMount() {
this.props.getParentRoute("/app");
}
componentDidMount() {
this.loadWorkoutData();
}
componentWillUpdate(nextProps, nextState) {
if (this.state.workoutName !== nextState.workoutName) {
this.props.getRouteName(nextState.workoutName);
}
}
componentWillReceiveProps(nextProps) {
if (this.props.params.id !== nextProps.params.id) this.fetchData(nextProps.params.id);
}
loadWorkoutData() {
this.props.setFethingData(true);
this.fetchData(this.props.params.id);
}
fetchData(id) {
fetch(`/api/v1/workout/training/${id}`)
.then(data => {
this.props.setFethingData(false);
if (data.status === 404) throw Error(404);
return data.json();
})
.then(data => {
this.setState({
workoutName: data.title,
workoutData: data.exercises.sort((a,b) => b.priority - a.priority)
});
})
.catch (error => {
if (error.message === "404") this.props.checkIsPageExist(false);
});
}
handleDeletingWorkoutItem(itemId) {
return () => {
const confirmDeleting = confirm("Вы действительно хотите удалить уражнение?");
if (confirmDeleting) {
fetch(`/api/v1/workout/exercise/${itemId}`, {
credentials: "include",
method: "DELETE",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": Token
}
})
.then(data => {
if (data.status === 204) {
const newState = this.state.workoutData.filter(session => !(session.url === data.url));
this.setState({
workoutData: newState
});
}
});
}
};
}
toggleItemFullData(e) {
const allFullDataItems = [...document.querySelectorAll(".workout-item__wrapper")];
allFullDataItems.forEach(item => {
const isItemFullDataClose = item.classList.contains("workout-item__wrapper_closed");
if (e.target.nextSibling === item) this.animateFullData(e.target.nextSibling, !isItemFullDataClose);
else if (!isItemFullDataClose) this.animateFullData(item, true);
});
}
animateFullData(item, isShown) {
let height;
item.classList.toggle("workout-item__wrapper_closed");
animation(item, "collapse", {
start() {
const itemHeight = `${item.offsetHeight}px`;
if (!isShown) {
item.style.height = "";
height = item.offsetHeight;
}
item.style.height = itemHeight;
},
active() {
item.style.height = `${isShown ? 0 : height}px`;
},
end() {
if (!isShown) item.style.height = "";
}
});
}
render() {
return (
<Workout
workoutData={this.state.workoutData}
toggleItemFullData={this.toggleItemFullData}
sessionId={this.props.params.id}
deleteItem={this.handleDeletingWorkoutItem}
/>
);
}
}
export default WorkoutContainer;
Выбор MVC или FLUX не очень-то и влияет на качество кода!
Я опасаюсь, что мы потерпели поражение в борьбе со сложностью систем
— Эдсгер Вибе Дейкстра
— Что сделано в Angular2 чтобы помочь разработчикам?
— Давайте сравним!
Анатомия для компонента
Декораторы
function superhero(target) {
target.isSuperhero = true;
target.power = 'flight';
}
@superhero
class MySuperHero {}
console.log(MySuperHero.isSuperhero);
<widget />
<widget />
Модель для страны Country.ts
export class Country {
constructor(
public id: string,
public label: string,
public coords: string) { }
}
Код для виджета Widget.ts
@Component({
selector: 'widget',
template: `<tab-bar [data]="list"
(onTabSelect)="select($event)"></tab-bar>
<map [item]="country"></map>`,
directives: [TabBar, StaticMap]
})
export class Widget {
list: Country[] = countries;
country: Country = new Country();
select(c:Country) {
this.country = c;
}
}
<map [item]="country">
Код для Map.ts
@Component({
selector: 'map',
template: `
<img *ngIf="item.coords"
src="https://maps.googleapis.com/maps/api/staticmap
?center={{item.coords}}
&zoom=5&size=400x400&
key=AIzaSyBAyMH-A99yD5fHQPz7uzqk8glNJYGEqus" />`,
})
export class StaticMap {
@Input()
item: Country;
}
<tab-bar [data]="list"(onTabSelect)="select($event)"></tab-bar>
export class TabBar {
...
@Output();
onTabSelect: EventEmitter<Country>;
...
onClick(tab:Country) {
this.active = tab;
this.onTabSelect.emit(tab);
}
}
}
Вниз - @Input
Вверх - @Output
Было: ES5, Dart
Cтало: ES6, ES5, Typescript, Dart
Было: ES5, Dart
Cтало: ES6, ES5, Typescript , Dart
У нас появилась опциональная типизация
Зачем мне типизация!?
Типизация на уровне фреймворка
Типизированные компоненты
@Component({
selector: 'countdown-parent-vc',
template: `<countdown-timer></countdown-timer>`,
})
export class CountdownComponent {
@ViewChild(CountdownTimerComponent)
private timerComponent: CountdownTimerComponent;
...
}
Можно вызывать методы прямо у таймера из кода класса
Angular1 — filters
{{movie.title | uppercase}}
Angular2 — pipes
{{movie.title | uppercase}}
Angular1
<input ng-model="vm.favoriteHero"/>
Angular2 — pipes
<input [(ngModel)]="favoriteHero" />
Angular1
<div ng-class="{active: isActive,
shazam: isImportant}">
Angular2
<div [ngClass]="{active: isActive,
shazam: isImportant}">
<div [class.active]="isActive">
export class Widget {
constructor() {
this.api = new APIWrapper();
}
}
export class Widget {
constructor() {
this.api = new APIWrapper(this.key);
}
}
Искать по всему коду?
angular.module('myModule', [])
.factory('serviceId', ['depService', function(depService) {
// ...
}])
interface API {
url:string;
}
@Injectable()
class APIImpl implements API {
url: string;
}
@NgModule({
providers: [{ provide: API, useClass: APIImpl }],
bootstrap: [Widget]
})
export class AppModule { }
@Component({
selector: 'my-heroes',
providers: [API],
})
export class Widget { }
Shadow DOM
Эмуляция Shadow DOM
[_nghost-pmm-5] {
display: block;
border: 1px solid black;
}
h3[_ngcontent-pmm-6] {
background-color: white;
border: 1px solid #777;
}
Изолирование стилей можно отключить
Спасибо за внимание!