Skip to content

Instantly share code, notes, and snippets.

@JBreit
Created November 5, 2018 22:12
Show Gist options
  • Save JBreit/93ecf5e9dea985874d67ab954b3101b2 to your computer and use it in GitHub Desktop.
Save JBreit/93ecf5e9dea985874d67ab954b3101b2 to your computer and use it in GitHub Desktop.
export const ADD_TODO = '[Todo] Add Todo';
export const REMOVE_TODO = '[Todo] Remove Todo';
export class AddTodo {
readonly type = ADD_TODO;
constructor(private payload: any) {}
}
export class RemoveTodo {
readonly type = REMOVE_TODO;
constructor(private payload: any) {}
}
import * as fromStore from './store';
import { renderTodos } from './utils';
const input = document.querySelector('input') as HTMLInputElement;
const button = document.querySelector('button') as HTMLButtonElement;
const destroy = document.querySelector('.unsubscribe') as HTMLButtonElement;
const todoList = document.querySelector('.todos') as HTMLLIElement;
const reducers = {
todos: fromStore.reducer,
};
const store = new fromStore.Store(reducers);
button.addEventListener('click', () => {
if (!input.value.trim()) return;
const todo = { label: input.value, complete: false };
store.dispatch(new fromStore.AddTodo(todo));
input.value = '';
}, false);
const unsubscribe = store.subscribe((state: any) => {
renderTodos(state.todos.data);
});
destroy.addEventListener('click', unsubscribe, false);
todoList.addEventListener('click', function (event) {
const target = event.target as HTMLButtonElement;
if (target.nodeName.toLowerCase() === 'button') {
const todo = JSON.parse(target.getAttribute('data-todo') as any);
store.dispatch(new fromStore.RemoveTodo(todo));
}
});
store.subscribe((state: any) => console.log('STATE:::', state));
<!DOCTYPE html>
<html lang="en">
<head>
<base href="/">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TypeScript Greeter</title>
</head>
<body>
<div id="app-root" role="app">
<p>You have <span></span> todos.</p>
<input type="text">
<button type="button" class="addTodo">Add todo</button>
<ul class="todos"></ul>
<button type="button" class="unsubscribe">Unsubscribe</button>
</div>
<script src="app.js"></script>
</body>
</html>
import * as fromActions from './actions';
export const initialState = {
loaded: false,
loading: false,
data: [{ label: 'Test Todo Application', complete: false }],
};
export function reducer(state = initialState, action: { type: string, payload: any }) {
switch (action.type) {
case fromActions.ADD_TODO: {
const todo = action.payload;
const data = [...state.data, todo];
return {
...state,
data,
};
}
case fromActions.REMOVE_TODO: {
const data = state.data.filter(todo => todo.label !== action.payload.label);
return {
...state,
data,
};
}
}
return state;
}
export class Store {
private subscribers: Function[];
private reducers: { [key: string]: Function };
private state: { [key: string]: any };
constructor(reducers = {}, initialState = {}) {
this.subscribers = [];
this.reducers = reducers;
this.state = this.reduce(initialState, {});
}
get value() {
return this.state;
}
subscribe(fn: any) {
this.subscribers = [...this.subscribers, fn];
this.notify();
return () => {
this.subscribers = this.subscribers.filter(sub => sub !== fn);
};
}
dispatch(action: any) {
console.log(action);
this.state = this.reduce(this.state, action);
this.notify();
console.log(this.state);
}
private notify() {
this.subscribers.forEach(fn => fn(this.value));
}
private reduce(state: any, action: any) {
const newState: any = {};
for (const prop in this.reducers) {
newState[prop] = this.reducers[prop](state[prop], action);
}
return newState;
}
};
const span = document.querySelector('span') as HTMLSpanElement;
const todoList = document.querySelector('.todos') as HTMLLIElement;
export function renderTodos(collection: any) {
if (span && todoList) {
span.innerHTML = collection.length;
todoList.innerHTML = '';
for (const item of collection) {
todoList.innerHTML = `
<li>
${item.label}
<button type="button" data-todo='${JSON.stringify(item)}'>
Delete
</button>
</li>
`;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment