Skip to content

Instantly share code, notes, and snippets.

@AndreyChechel
Created November 25, 2017 23:04
Show Gist options
  • Save AndreyChechel/e53db2e0dd40866a17a28f3ad310b20d to your computer and use it in GitHub Desktop.
Save AndreyChechel/e53db2e0dd40866a17a28f3ad310b20d to your computer and use it in GitHub Desktop.
Retyped.angular in action
using Bridge;
using System;
using System.Collections.Generic;
using Retyped;
namespace AngularDemo
{
public class App
{
[Init]
public static void Start()
{
// See original sample here: https://docs.angularjs.org/guide/services
// Create controller arguments:
var myControllerInjectableArgs = new Union<string, angular.angular2.IControllerConstructor.IControllerConstructorFn>[]
{
"$scope",
"notify",
new angular.angular2.IControllerConstructor.IControllerConstructorFn(args =>
{
// args are supposed to represent "params object[] args",
// but it could not be working applied to delegates.
// An issue will be created to adapt the syntax to the expected behaviour.
// As a workaround, 'Bridge.Arguments' will be used instead:
args = Arguments.ToArray();
var scope = args[0];
var notify = (Action<string>) args[1];
scope["callNotify"] = new Action<string>(msg =>
{
notify(msg);
});
return null;
})
};
// Construct service arguments:
var notifyFactoryArgs = new Union<string, Delegate>[]
{
"$window",
new Func<dom.Window, Action<string>>(win =>
{
var msgs = new List<string>();
var handlerFn = new Action<string>(msg =>
{
msgs.Add(msg);
if (msgs.Count == 3)
{
win.alert(string.Join("\n", msgs));
msgs.Clear();
}
});
return handlerFn;
})
};
// Declare module with a controller and a service:
var module = angular.angular3.module("myServiceModule", Foo);
module
.controller("MyController", ToInjectableControllerCtr(myControllerInjectableArgs))
.factory("notify", ToInjectableFn(notifyFactoryArgs));
}
[Template("[]")]
public static string[] Foo;
public static angular.angular2.Injectable<angular.Function> ToInjectableFn(Delegate fn)
{
// Any C# delegate is implicitly convertable to "es5.Function".
// Based on d.ts file, angular extends "es5.Function" with an additional member,
// So it's not actually a new type in TypeScript, but a new type-inheritor in C#.
// We can just use any way of casting (direct cast, As<> method, casting method with a proper template attribute):
var angularFn = (angular.Function)fn;
// Injectable<T> is a type alias for a T or an Array of string/T (T is "Delegate" here).
// So we can safely cast "angularFn" to "Injectable<Function>" entity:
var injectable = (angular.angular2.Injectable<angular.Function>) angularFn;
return injectable;
}
public static angular.angular2.Injectable<angular.Function> ToInjectableFn(Union<string, Delegate>[] args)
{
// That overload allows to create injectables based on arrays of string/functions.
// For sake of simplicity and better performance we'll do "unsafe" cast (.As<>), based
// on the assumption that "Delegate" is convertable to "angular.Function".
// That could be also done using a loop to avoid unsafe cast (that could be tricky though).
var strsOrCtrs = args.As<Union<string, angular.Function>[]>();
// Convert C# array into es5.Array:
// An issue will be created for that: es5.Array needs to be implicitly convertible to C# array
var es5Array = strsOrCtrs.As<es5.Array<Union<string, angular.Function>>>();
// Injectable<T> is a type alias for an Array of string/T (T is "angular.Function" here).
// So we can safely cast "es5Array" to "Injectable<angular.Function>" entity:
var injectable = (angular.angular2.Injectable<angular.Function>) es5Array;
return injectable;
}
public static angular.angular2.Injectable<angular.angular2.IControllerConstructor> ToInjectableControllerCtr(angular.angular2.IControllerConstructor.IControllerConstructorFn fn)
{
// Based on d.ts file, "IControllerConstructor" is a type alias for a union of constructor/self functions.
// That means any C# delegate with proper signature (see "IControllerConstructorFn" delegate)
// can be implicitly casted to "IControllerConstructor" entity.
angular.angular2.IControllerConstructor controllerCtr = fn;
// Injectable<T> is a type alias for a T or an Array of string/T (T is "IControllerConstructor" here).
// So we can safely cast "controllerCtr" to "Injectable<Function>" entity:
var injectable = (angular.angular2.Injectable<angular.angular2.IControllerConstructor>)controllerCtr;
return injectable;
}
public static angular.angular2.Injectable<angular.angular2.IControllerConstructor> ToInjectableControllerCtr(Union<string, angular.angular2.IControllerConstructor.IControllerConstructorFn>[] args)
{
// That overload allows to create injectables based on arrays of string/functions.
// For sake of simplicity and better performance we'll do "unsafe" cast (.As<>), based
// on the assumption that "IControllerConstructorFn" is convertable to "IControllerConstructor".
// That could be also done using a loop to avoid unsafe cast (that could be tricky though).
var strsOrCtrs = args.As<Union<string, angular.angular2.IControllerConstructor>[]>();
// Convert C# array into es5.Array:
// An issue will be created for that: es5.Array needs to be implicitly convertible to C# array
var es5Array = strsOrCtrs.As<es5.Array<Union<string, angular.angular2.IControllerConstructor>>>();
// Injectable<T> is a type alias for an Array of string/T (T is "IControllerConstructor" here).
// So we can safely cast "es5Array" to "Injectable<IControllerConstructor>" entity:
var injectable = (angular.angular2.Injectable<angular.angular2.IControllerConstructor>)es5Array;
return injectable;
}
}
}
{
// Specific option for accessing Angular through global variables:
"loader": {
"manualLoading": "true",
"skipManualVariables": "true"
},
//...
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Retyped.angular demo</title>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js'></script>
<script src="js/bridge.js"></script>
<script src="js/bridge.console.js"></script>
<script src="js/AngularDemo.js"></script>
</head>
<body ng-app="myServiceModule">
<div id="simple" ng-controller="MyController">
<p>Let's try this simple notify service, injected into the controller...</p>
<input ng-init="message='test'" ng-model="message" >
<button ng-click="callNotify(message);">NOTIFY</button>
<p>(you have to click 3 times to see an alert)</p>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment