TypeScript uMVC based on <https://github.com/petermichaux/uMVC>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class Observer { | |
abstract update(data?: any): void | |
} | |
abstract class Observable { | |
protected _observers: Observer[] = [] | |
observe(observer: Observer) { | |
if (this._observers.indexOf(observer) > -1) | |
throw new Error('Observer already added') | |
this._observers.push(observer) | |
} | |
unobserve(observer: Observer) { | |
if (this._observers.indexOf(observer) == -1) | |
throw new Error('Observer does not exist') | |
this._observers = this._observers.filter(o => o === observer) | |
} | |
notify(data: any) { | |
// copy array before update in case one of the updates modifies the array | |
this._observers.slice(0).forEach(o => o.update(data)) | |
} | |
} | |
abstract class Model extends Observable {} | |
abstract class View extends Observer { | |
protected _parent?: View | |
protected _subViews: View[] = [] | |
constructor(protected _model: Model, protected _controller: Controller) { | |
super() | |
} | |
getController() { | |
return this._controller | |
} | |
getModel() { | |
return this._model | |
} | |
setModel(model: Model) { | |
this._setModelAndController(model, this._controller) | |
} | |
setController(controller: Controller) { | |
this._setModelAndController(this._model, controller) | |
} | |
protected _setModelAndController(model: Model, controller: Controller) { | |
if (this._model !== model) { | |
this._model.unobserve(this) | |
model.observe(this) | |
this._model = model | |
} | |
controller.setView(this) | |
controller.setModel(model) | |
this._controller = controller | |
} | |
getSubViews() { | |
return new Array(this._subViews) | |
} | |
addSubView(subView: View) { | |
var previousSuperView = subView.getSuperView() | |
if (previousSuperView) | |
previousSuperView.removeSubView(subView) | |
this._subViews.push(subView) | |
subView.setParent(this) | |
} | |
removeSubView(subView: View) { | |
this._subViews = this._subViews.filter(s => { | |
if(s === subView) | |
s.setParent(undefined) | |
return s !== subView | |
}) | |
} | |
setParent(parent?: View) { | |
this._parent = parent | |
} | |
getSuperView() { | |
return this._parent | |
} | |
destroy() { | |
this._model.unobserve(this) | |
this._subViews.forEach(s => s.destroy()) | |
} | |
} | |
abstract class Controller { | |
protected _model?: Model | |
protected _view?: View | |
getModel(): Model | undefined { | |
return this._model | |
} | |
setModel(model?: Model) { | |
this._model = model | |
} | |
getView(): View | undefined { | |
return this._view | |
} | |
setView(view?: View) { | |
this._view = view | |
} | |
} | |
export {Model, View, Controller} |
Line 8: arrow function missing logical not.
Thanks for the comment. I've changed the implementation to TypeScript to make the usage clearer. You can compile this to the version of JavaScript desired here.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very nice example!
While copying into my notebook, I noticed 2 tiny errors. Line 31: misleading indentation. Line 76: missing underscore in '_subViews'.