Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
knockout-decorators
Advanced tools
Decorators for use Knockout JS in TypeScript and ESNext environments
Decorators for use Knockout JS in TypeScript and ESNext environments
import { observable, computed, component } from "knockout-decorators";
@component("person-view", `
<div>Name: <span data-bind="text: fullName"></span></div>
<div>Age: <span data-bind="text: age"></span></div>
`)
class PersonView {
@observable firstName: string;
@observable lastName: string;
@observable age: string;
@computed get fullName() {
return this.firstName + " " + this.lastName;
}
constructor({ firstName, lastName, age }, element, templateNodes) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
}
Property decorator that creates hidden ko.observable
with ES6 getter and setter for it
class Model {
@observable field = 123;
};
let model = new Model();
ko.computed(() => { console.log(model.field); }); // [console] ➜ 123
model.field = 456; // [console] ➜ 456
Property decorator that creates hidden ko.observableArray
with ES6 getter and setter for it
class Model {
@observableArray array = [1, 2, 3];
};
let model = new Model();
ko.computed(() => { console.log(model.field); }); // [console] ➜ [1, 2, 3]
model.field = [4, 5, 6]; // [console] ➜ [4, 5, 6]
Functions from ko.observableArray
(both Knockout-specific remove
, removeAll
, destroy
, destroyAll
, replace
and redefined Array.prototype
functions pop
, push
, reverse
, shift
, sort
, splice
, unshift
)
are also presents in decorated poperty.
They works like if we invoke them on hidden ko.observableArray
.
And also decorated array has a subscribe
function from ko.subscribable
class Model {
@observableArray array = [1, 2, 3];
};
let model = new Model();
model.array.subscribe((changes) => { console.log(changes); }, null, "arrayChange");
model.array.push(4); // [console] ➜ [{ status: 'added', value: 4, index: 3 }]
model.array.remove(val => val % 2 === 0); // [console] ➜ [{ status: 'deleted', value: 2, index: 1 },
// { status: 'deleted', value: 4, index: 3 }]
Accessor decorator that wraps ES6 getter and setter (if defined) to hidden ko.pureComputed
class Person {
@observable firstName = "";
@observable lastName = "";
@computed
get fullName() { return this.firstName + " " + this.lastName; }
set fullName(value) { [this.firstName, this.lastName] = value.trim().split(/\s+/g); }
}
let person = new Person();
ko.pureComputed(() => person.fullName).subscribe(console.log.bind(console));
person.fullName = " John Smith " // [console] ➜ "John Smith"
Replace original method with factory that produces ko.computed
from original method
@observer
@observer(autoDispose: boolean)
Argument | Default | Description |
---|---|---|
autoDispose | true | if true then computed will be disposed when entire decorated class is disposed |
Method that decorated with @observer
evaluates once when explicitely invoked (this call creates hidden ko.computed
)
and every times when it's observable (or computed) dependencies are changed.
Hidden ko.computed
will be disposed when entire decorated class is disposed (if we don't set autoDispose
to false
)
class BlogPage {
@observable postId = 0;
@observable pageData: any;
constructor(blogId: ko.Observable<number>) {
const computed = this.onRoute(blogId);
// subscribe onRoute handler to changes
// then we can do whatever with created computed
}
// 'dispose()' method is redefined such that it disposes hidded 'onRoute' computed
// if original class already has 'dispose()' method then it would be wrapped by new method
@observer async onRoute(blogId: ko.Observable<number>) {
const resp = await fetch(`/blog/${ blogId() }/post/${ this.postId }`);
this.pageData = await resp.json();
}
}
Apply extenders to decorated @observable
@extend(extenders: Object)
@extend(extendersFactory: () => Object)
Extenders can be defined by plain object or by calling method, that returns extenders-object.
Note that extendersFactory
invoked with ViewModel instance as this
argument.
class ViewModel {
rateLimit: 50;
@extend({ notify: "always" })
@observable first = "";
@extend(ViewModel.prototype.getExtender)
@observable second = "";
getExtender() {
return { rateLimit: this.rateLimit };
}
}
Subscribe to @observable
by name or by specifying callback explicitely
@subscribe(callback: (value: any) => void, event?: string, autoDispose?: boolean)
@subscribe(targetOrCallback: string | symbol, event?: string, autoDispose?: boolean)
Argument | Default | Description |
---|---|---|
callback | Subscription handler method | |
targetOrCallback | Name of subscription handler method or name of @observable property | |
event | null | Knockout subscription event |
autoDispose | true | if true then computed will be disposed when entire decorated class is disposed |
We can define name of handler when we decorate @observable
or define name of @observable
when decorate handler.
Subscriptions will be disposed when entire decorated class is disposed (if we don't set autoDispose
to false
)
class ViewModel {
// specify callback
@subscribe("onFirstChanged")
@observable first = "";
onFirstChanged(value) {}
@observable second = "";
// specify observable
@subscribe("second")
onSecondChanged(value) {}
}
Also whe can pass subscription handler directly.
Then it will be invoked with ViewModel instance as this
argument.
And we can specify subscription event
class ViewModel {
operationLog = [];
@subscribe(ViewModel.prototype.onArrayChange, "arrayChange")
@observableArray array = [1, 2, 3]
onArrayChange(changes) {
this.operationLog.push(...changes);
}
}
Shorthand for registering Knockout component by decorating ViewModel class
@component(name: string, options?: Object);
@component(name: string, template: any, options?: Object);
@component(name: string, template: any, styles: any, options?: Object);
Argument | Default | Description |
---|---|---|
name | Name of component | |
template | "<!---->" | Knockout template definition |
styles | Ignored parameter (used for require() styles by webpack etc.) | |
options | { synchronous: true } | Another options that passed directly to ko.components.register() |
By default components registered with synchronous
flag.
It can be overwritten by passing { synchronous: false }
as options.
If template is not specified then it will be replaced by HTML comment <!---->
If ViewModel constructor accepts zero or one arguments,
then it will be registered as viewModel:
in config object.
@component("my-component")
class Component {
constructor(params: any) {}
}
// ▼▼▼ results to ▼▼▼
ko.components.register("my-component", {
viewModel: Component,
template: "<!---->",
synchronous: true,
});
If ViewModel constructor accepts two or three arguments,
then createViewModel:
factory is created
and { element, templateNodes }
are passed as arguments to ViewModel constructor.
@component("my-component",
require("./my-component.html"),
require("./my-component.css"), {
synchronous: false,
additionalData: { foo: "bar" } // consider non-standard field
})
class Component {
constructor(
private params: any,
private element: Node,
private templateNodes: Node[]
) {}
}
// ▼▼▼ results to ▼▼▼
ko.components.register("my-component", {
viewModel: {
createViewModel(params, { element, templateNodes }) {
return new Component(params, element, templateNodes);
}
},
template: require("./my-component.html"),
synchronous: false,
additionalData: { foo: "bar" } // consider non-standard field
});
layout.html
<script src="/{path_to_vendor_scrpts}/knockout.js"></script>
<script src="/{path_to_vendor_scrpts}/knockout-decorators.js"></script>
script.ts
namespace MyTypescriptNamespace {
// import from TypeScript namespace (JavaScript global variable)
const { observable, computed } = KnockoutDecorators;
export class MyClass {
@observable field = "";
}
}
[0.5.0] - 2016-12-10
FAQs
Decorators for use Knockout JS in TypeScript and ESNext environments
The npm package knockout-decorators receives a total of 0 weekly downloads. As such, knockout-decorators popularity was classified as not popular.
We found that knockout-decorators demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.