Define a custom jQuery UI widget in TypeScript - jquery-ui

We're currently looking at translating our JavaScript project to TypeScript. Our application relies heavily on custom developed jQuery UI widgets.
In our current code base, we're using a deep copy mechanism to inherit from widget definitions allowing us, for example, to declare a generic TableWidget as well as an OrdersTableWidget which defines more specific functions.
Therefore, I'd like to define my widget definitions as TypeScript classes and then bind an instance of these classes to jQuery.
For example
class MyWidget {
options: WidgetOptions;
_init(){
// general initialization
}
}
class MySecondWidget extends MyWidget {
_init(){
super._init();
// specific initialization
}
}
And then
$.widget("MyNameSpace.MyWidget", new MyWidget());
$.widget("MyNameSpace.MySeWidget", new MyWidget());
Furthermore, I'd like to denote my custom widgets as implementations of jQuery UI's Widget definition
class MyWidget implements Widget {
options: WidgetOptions;
_init(){
// general initialization
}
}
so I'm able to use the following syntax in TypeScript:
$(selector).MyWidget(options);
I know I have to work with the definition file (from DefinitelyTyped), however I have not yet found a reliable source explaining me how I should write custom jQuery UI Widgets in TypeScript. Has anyone got experience with this?
Any help greatly appreciated, as always!

I'm not sure you can write a class that implements the Widget interface, due to the lack of overloaded constructors. You could create a variable that is typed by the Widget interface.
A standard jQuery plugin would be represent in almost pure JavaScript and wouldn't use modules or classes as it ends up being wrapped up as part of jQuery, which itself isn't a module or class.
Here is an empty plugin called plugin that looks like any standard jQuery plugin, but you can see it takes advantage of the TypeScript type system and extends the JQuery interface to allow it to be called.
/// <reference path="jquery.d.ts" />
interface JQuery {
plugin(): JQuery;
plugin(settings: Object): JQuery;
}
(function ($) {
function DoSomething(someParamater: string) : void {
}
$.fn.plugin = function (settings) {
var config = {
settingA: "Example",
settingB: 5
};
if (settings) {
$.extend(config, settings);
}
return this.each(function () {
});
};
})(jQuery);
This would be called in the normal way.
$('#id').plugin();
So really, my answer is - you can't really do what you want because you are adding to the declared interfaces for jQuery rather than exposing them as modules. You could wrap the usage in a module, like an adaptor that abstracts the jQuery aspect away from the use in your TypeScript, or you can call your classes from inside the plugin, but the plugin or widget doesn't really fit into a module or class.

It might help to have a base class in typescript from which other widget classes may derive.
Its only purpose is to provide the base class semantic so you can access the base class'es members without having to resort to weak typing.
The trick is to remove all the members at runtime (in the constructor) -- otherwise you run into problems with the inheritance provided by the widget factory. For example, the option method would override the widget's original method which is not desired: we just want to be able to call it (in a statically typed way).
class WidgetBase {
public element:JQuery;
constructor() {
// remove all members, they are only needed at compile time.
var myPrototype = (<Function>WidgetBase).prototype;
$.each(myPrototype, (propertyName, value)=>{
delete myPrototype[propertyName];
});
}
/**
* Calles the base implementation of a method when called from a derived method.
* #private
*/
public _super(arg1?:any, arg2?:any, arg3?:any, arg4?:any) {
}
/**
* #private
*/
public _superApply(arguments) {
}
/**
* Gets or sets the value of the widget option associated with the specified optionName.
*/
public option(optionName:string, value?:any):any {
}
// ... further methods from http://api.jqueryui.com/jQuery.widget/
}
Then you can implement your own widget like this:
class SmartWidget extends WidgetBase {
constructor(){
super();
}
public _create() {
var mySmartOption = this.option('smart'); // compiles because of base class
this.beSmart(mySmartOption);
}
public _setOption(key:string, value:any) {
if (key === 'smart') {
this.beSmart(value);
}
this._super(key, value); // compiles because of base class
}
private beSmart(smartOne:any){
// ...
}
}
// register
jQuery.widget("myLib.smartWidget", new SmartWidget());
// assuming you are using https://github.com/borisyankov/DefinitelyTyped
declare interface JQuery{
smartWidget();
smartWidget(options:any);
smartWidget(methodName:string, param1?:any, param2?:any, param3?:any, param4?:any);
}
And finally, you can use your widget:
$(".selector").smartWidget({smart:"you"});

Related

How to write some arbitrary initialization code in a Dart mixin?

Say I have a package that exposes a mixin that provides some extensibility through an API:
mixin ListenerModifier<T> {
T get value;
void addListener(Callback callback);
void removeListener(Callback callback);
}
Say I want to make a "plugin" based on this mixin:
mixin PreviousValue<T> on ListenerModifier<T> {
late T previous;
const PreviousValue() {
addListener(() => previous = value);
}
}
(You could also have plugins defined in other packages as well, perhaps to expose a Stream<T> getter.)
Then, a user could use any plugins at will, like this:
abstract class MyListener<T> with ListenerModifier<T>, PreviousValue<T> {}
The issue is, mixins can't have constructors like the above PreviousValue assumes. Is there some OOP/architectural way to get around this problem? I initially thought of just forcing users of PreviousValue (for example) to call a registerPreviousValue() method in their MyListener constructor as a workaround, but that is highly error prone.
Related:
How to group mixins in Dart?
How can I initialize a mixin's immutable data in Dart?
Just realized for the particular example I gave, I can use a different sort of plugin system without mixins:
mixin ListenerModifierPluginAPI {
T get value;
void addListener(Callback callback);
void removeListener(Callback callback);
}
abstract class ListenerModifier with ListenerModifierPluginAPI {
T registerPlugin<T>(T Function(ListenerModifierPluginAPI) plugin) => plugin(this);
}
class MyListenerModifier extends ListenerModifier {
late final PreviousValueState previousValueState;
const MyListenerModifier() {
previousValueState = registerPlugin(previousValuePlugin);
}
// ...
}
This may not work for all people though. If someone has a different solution, I am all ears.

How to get a "constructor" or a factory without reflection in Flutter

As Flutter has no reflection (due to tree shaking) I need to find a way to create Objects of a specific Type at runtime and I would strongly prefere to do it without code generation. So I think the best way to register a Type to be created like this would be the following:
class Test with Bindable {
static Test create() {
return new Test();
}
}
registerTest() {
registerType<Test>("test", Test.create);
}
void registerType<T extends Bindable>(String s, T Function() create) {}
Any other ideas?

Reflectable: myAnnotation.annotatedClasses different result CmdApp<>Client

Say I have the following Annotation and 2 classes:
class AppModel extends Reflectable {
final String name;
const AppModel([this.name])
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
#appModel
class ImGonnaBePickedUp {
}
#AppModel(' :( ')
class AndImNotPickedUpOnServer_IDoOnWebClient {
}
main() {
appModel.annotatedClasses // that's what I mean by "Picked Up".
}
On CmdApp side (Server): only AndImNotPickedUpOnServer_IDoOnWebClient is given in appModel.annotatedClasses.
On the web side, both classes are given.
Long story short, how do I retrieve classes annotated with direct const constructor calls like in the example above #AppModel(' :( ') (for both CmdApp and Web)?
since version 0.5.4 reflectable classes doesn't support constructors with arguments
This appears in reflectable documentation:
Footnotes: 1. Currently, the only setup which is supported is when the metadata object is an instance of a direct subclass of the class [Reflectable], say MyReflectable, and that subclass defines a const constructor taking zero arguments. This ensures that every subclass of Reflectable used as metadata is a singleton class, which means that the behavior of the instance can be expressed by generating code in the class. Generalizations of this setup may be supported in the future if compelling use cases come up.
one possible solution could be to use a second annotation to handle the name, for example:
import 'package:reflectable/reflectable.dart';
import 'package:drails_commons/drails_commons.dart';
class AppModel extends Reflectable {
const AppModel()
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
class TableName {
final String name;
const TableName(this.name);
}
#appModel
class ImGonnaBePickedUp {
}
#appModel
#TableName(' :( ')
class AndImNotPickedUpOnServer_WorksOnWebClient {
}
main() {
print(appModel.annotatedClasses); // that's what I mean by "Picked Up".
print(new GetValueOfAnnotation<TableName>()
.fromDeclaration(appModel.reflectType(AndImNotPickedUpOnServer_WorksOnWebClient)).name);
}
Note: I'm also using drails_common package

Dagger: Override #Provides-Method in Scoped Module

Let us suppose the following situation. There is a global module AppModule, a scoped module ScopedModule, a class Main and a class Foo in an application's main variant. Moreover, there is a debug variant with a module DebugAppModule, a module DebugScopedModule and a class Bar. Only the debug variant may know about Bar.
The main variant contains the following relevant code excerpts.
#Module AppModule { /*..*/ }
#Module(injects=Main.class, addsTo=AppModule.class)
ScopedModule { #Provides Foo provideFoo() { return new Foo(); } }
class Main { scopedGraph = graph.plus(new ScopedModule(this)); }
class Foo { /*..*/ }
// In the entry point of the application
ObjectGraph.create(new AppModule());
The debug variant contains the following relevant code excerpts.
#Module(addsTo=AppModule.class, overrides=true) DebugAppModule { /*..*/ }
#Module(injects=Main.class, addsTo=DebugAppModule.class, overrides=true)
DebugScopedModule { #Provides Foo provideFoo() { return new Bar(); } }
class Bar extends Foo { /*..*/ }
// In the entry point of the application
ObjectGraph.create(new AppModule(), new DebugAppModule());
My research and experimentation revealed that it is not possible to override #Provides-methods in scoped modules, i.e. when plusing a module. See for example How to Mock Dagger Activity Object Graphs. That is, in the debug variant whenever a Foo is injected it still would be a Foo and not a Bar. This makes sense because the class Main has a fixed dependency to ScopedModule (note the new).
It seems to me that there should be a way to inject scoped modules themselves – meta-injection so to say :). That is, AppModule could provide ScopedModule for Main. The problem is that ScopedModule's constructor needs an instance of Main and so AppModule would need to retain an instance of Main and that would not fly (e.g. in an Android-specific context where Main would be an Activity).
So what is the best alternative way to achieve the effect of overriding #Provides-methods when using scoped modules?
With the latest version of Dagger, overriding #Provided methods are not permitted.
I found a good solution here. Thanks to #vaughandroid
Basically,
When you are providing your module into your component, you can override your methods.
MyComponent component = DaggerMyComponent.builder()
.appModule(new AppModule() {
#Override public Foo provideFoo() {
return new Bar();
}
})
.build();
This has worked for me and I guess it'll work for you.

Extend svg.RectElement (factory constructor)

I begin with Dart and I would like to extend RectElement class to create a MyRectElement class which is able to move rectangle in SVG area :
import 'dart:html';
import 'dart:svg';
class MyRectElement extends RectElement{
int xOrigin;
int yOrigin;
factory MyRectElement() {
}
}
void main() {
var rect = new MyRectElement();
var container = querySelector("#container");
container.append(rect);
}
But RectElement has a factory constructor.
I must admit that I don't understand factory constructor even if I read lots of posts about it...
What should I put in MyRectElement factory contructor ?
Extending just the class is not supported.
You can build a Polymer element that extends a DOM element or if you don't want to use Polymer this question should provide some information Is it possible to create a Polymer element without Html?

Resources