Looking at Backbonejs' implementation of the extend function, it shows that it isn't a basic prototype extension, and when backbone extensions are converted straight to TypeScript classes some things stop functioning. What is the right way to convert each component of Backbonejs (Model, Collection, Route, View, History) to a typescript class and make sure nothing is broken?
Thanks!
Update:
The answer in this Q/A can also work for other backbone constructs.
This is because the code generated by TypeScript first calls the Router constructor and then declares the routes.
Code generated by TypeScript compiler
...
function AppRouter() {
_super.apply(this, arguments);
this.routes = { // <= routes defined after _super constructor
"*actions": "defaultRoute"
};
}
...
To fix this just call the Backbone Router function _bindRoutes() on your TypeScript object constructor.
Example:
class AppRouter extends Backbone.Router {
routes = {
"*actions": "defaultRoute"
}
constructor(){
super();
// call _bindRoutes() here function to bind your routes
(<any>this)._bindRoutes();
}
defaultRoute() {
document.write("Default Route Invoked");
}
}
var app_router = new AppRouter();
Backbone.history.start();
Download a sample code here
Related
I have an angularjs 1.7 component which I need to upgrade to angular 8 component. It has an external script, which I cannot modify. That script inserts an iframe into the div and it expects some settings from the component to customize the iframe.
The old component code:
angular.module('myApp.shared').component("userExternal", {
template: '<div id="userIframe"></div>',
controller: function ($window) {
this.scriptUrl = "//myurl/widget/addIframe.js";
this.$onInit = function () {
$window.UserSettings = [];
$window.UserSettings.push(['set', {
btn_color: '#008A00',
bg_color: 'white'
}]);
});
};
}
});
I have two problems here:
I don't know how to convert $widnow to angular 8 window object.
When I convert $window to angular 8 window, how can I add UserSettings array to it?
This is my angular 8 component, but my code did not work correctly.
HTML Template
<script src="//myurl/widget/addIframe.js"></script>
<div class="user_external></div>
TS Code
import { Component} from '#angular/core';
#Component({
selector: 'app-user',
templateUrl: './user-external.component.html'
})
export class UserExternalComponent {
constructor() {
}
ngOnInit() {
window.UserSettings = [];
window.UserSettings.push(['set', {
btn_color: '#008A00',
bg_color: 'white'
}]);
console.log(window);
}
}
Thank you
Following a combination of this tutorial for the window reference and this tutorial for upgrading from AngularJS to Angular in general, I created an injectable service that seems to be doing the job, at least so far in a downgraded context. (Next step is to start upgrading the modules that use the dependency, but I successfully replaced all AngularJS injections of $window with my new APIWindow class, and everything works as before with no breaking errors.)
Keeping in mind this is being used as a downgraded Angular class inside a currently mostly AngularJS app, the class looks like this:
// api.window.service.ts
import { Injectable } from '#angular/core'
import { downgradeInjectable } from '#angular/upgrade/static'
import * as angular from 'angular'
// You could change this to return any property on Window, but external is the one I use:
function _external (): any {
return window.external
}
#Injectable()
export class APIWindow {
get external (): any {
return _external()
}
}
angular
.module('APIModule')
.service('APIWindow', downgradeInjectable(APIWindow))
Hopefully this helps someone else with a similar situation following this upgrade path!
I'm new to reactjs. I want to know, is there an equivalent for angular services such as $rootScop, $q, $webSocket in reactJs?
code:
.service('a', function ($rootScope, $location, $q, $webSocket) {
this.init = function () {
b()
c()
}
For example code parameters above what equivalent in react? I know the equivalent $scope in react is this.state.
There is no such thing as services in react
here are alternatives.
$rootscope --> state, you can share it across components. (You can use redux for state management whose philosophy is one true source of data).
$q --> Es6 Promise
$websocket --> html5 websocket.
Some thing similar to service is you can write a Class or Function which takes all the required services as params and you can call it any where by exporting it.
some similar implementation you can use for react.
In service.js
const myService = (...otherServices) => {
doStuff1();
doStuff2();
return {
...items
}
}
export default myService;
In component.js
you can import it
import myService from './service';
import React from 'react';
class testComponent extends React.Component {
constructor(props){
super(props);
this.data = myService().getData(); //just an example.
}
render(){
return (
<div>{this.data}</div>
);
}
}
$rootScope -> it is an global scope object in angular, in react we use reducers to store data which will be accessible to all components
$q-> we have q library same as $q in react
$location -> we have transition/history inside instance of class/components
$webScocket-> t
here are multiple modules https://blog.pusher.com/making-reactjs-realtime-with-websockets/
Hello fellow stackoverflowers,
I've been trying for some time now without success to implement
lazy loading of angular components with the new component router (ngComponentRouter).
This is the code I used for the configuration of the main component:
//define main app component
app.value("$routerRootComponent","simpleTrackerApp");
//main app component config
var lazyLoaderMod = null;
var httpService = null;
app.component("simpleTrackerApp", {
/*#ngInject*/
controller:function ($ocLazyLoad,$http) {
lazyLoaderMod = $ocLazyLoad;
httpService = $http;
},
templateUrl: CONFIG_APP_SHARED_URL + 'mainComponent/simpleTrackerApp.html',
$routeConfig: [
{
useAsDefault:true,
path:"/bugs",
name:"Bugs",
loader: function () {
return lazyLoaderMod.load(CONFIG_APP_COMPONENTS_URL + 'bug/bugs/bugsCtrl.js');
}
},
{path:'/**',redirectTo:['Bugs']}
]
});
My first problem was I could'nt get it to work with ocLazyLoad injected in loader propety so I loaded it in the main controller and referenced it in the loader property.
After that when I finally got it working inside loader propety
I couldn't seem to get it to actually load the component I kept getting this error:
lib.js:2 TypeError: Cannot read property 'then' of undefined
at e._loader (http://simpletracker.co.il/client/production/app/lib.js:9:10670)
at e.resolveComponentType (http://simpletracker.co.il/client/production/app/lib.js:9:21463)
at e.recognize (http://simpletracker.co.il/client/production/app/lib.js:9:23535)
at http://simpletracker.co.il/client/production/app/lib.js:9:25949
at Array.forEach (native)
at e.recognize (http://simpletracker.co.il/client/production/app/lib.js:9:25921)
at e._recognize (http://simpletracker.co.il/client/production/app/lib.js:10:4834)
at e.recognize (http://simpletracker.co.il/client/production/app/lib.js:10:4605)
at t.e.recognize (http://simpletracker.co.il/client/production/app/lib.js:10:13656)
at http://simpletracker.co.il/client/production/app/lib.js:10:10757
Now I understand I'm obviously doing something wrong in the loader
and that I need to somehow register the component. but I couldn't find
any docs on angular for the loader and nobody else lazyloading components with the new router so I really couldn't figure how this could be achieved.
I'd really appreciate some help on this but I'm also wondering in general
if maybe it is premature to use angular component router
with its lack of documentation and support.
So I'd really like to hear from other expierenced angular programmers
their opinion on the matter.
Edit:Anyone have any insight on the matter?..
You could use $router instead of the http-service. Applied on your code:
app.component("simpleTrackerApp", {
templateUrl: 'mainComponent/simpleTrackerApp.html',
controller: ['$router', '$ocLazyLoad', function ($ocLazyLoad, $http) {
$router.config([
{
path: '/bugs/',
name: "Bugs",
loader: function () {
return $ocLazyLoad.load('/bugsFolder/bugs.component.js') //no url, set the path to your component
.then(function () {
return 'bugs' //name of your component
})
}
}
])
}],
});
And don't forget to inject your dependencies in the app.module.
I'm working with angular, jspm, and es6. I'm working with a base class to inject dependencies onto the constructor and automatically register themselves on 'this'.
This is actually a pattern that exists in React when you extend the base component class. I found this guy's little shortcut method here: http://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes
I am looking for a way to do this with Angular, using es6 Classes to bind the injected dependencies to the constructor's "this".
class baseClass {
constructor(...injections) {
this._bind(injections)
}
_bind(injections) {
injections.forEach( (injection) => {
this[injection.name] = injection;
});
}
}
class DiClass extends baseClass {
constructor($q, SomeAngularFactory) {
super($q, SomeAngularFactory);
}
}
This obviously doesn't work (injection.name is not a thing, i know)... but it almost does. My question is how do i get the "name" of the injected function or object. In this example, the _bind function just gives you the raw object or function... i don't know how to get "$q" or "SomeAngularFactory" as a string.
You can kind of get that by using "Object.getOwnPropertyNames(...injections)", but not inside the _bind function.
Thanks for any feedback or ideas you have.
You could do something like this:
class baseClass {
constructor(injections) {
Object.assign(this, injections);
}
}
class DiClass extends baseClass {
constructor($q, SomeAngularFactory) {
super({ $q, SomeAngularFactory });
}
}
Obs.: Like classes, Object.assign is an ES2015 feature and it merges the second (parameter) object into the first one.
In AngularJS this injectable arguments works only on development mode. If you go to production and minify your scripts, all injectables should be saved into special property. You can learn more about it in the angular docs. Here how it works with angular controllers
function MyController($q, SomeAngularFactory) {
}
MyController.$inject = ['$q', 'SomeAngularFactory']
Angular 2.0 will be powered by TypeScript and will use annotations to describe injectable variables. For now in anguar 1.3 you still can add static property $inject
class DiClass extends baseClass {
constructor($q, SomeAngularFactory) {
super($q, SomeAngularFactory);
}
}
DiClass.$inject = ['$q', 'SomeAngularFactory'];
Angular has a built in method, $injector.annotate(fn), which it uses for dependency injection, and which allows you to get arguments of the function you pass to it. You could utilize it to get the names of all constructor() parameters, and then use $injector.get() to retrieve them (which should be fine performance-wise, since they are cached).
Here's a link to answer in another thread, and a direct link to a fiddle with a demo.
In Backbone.Marionette documentation some statement puzzled me:
You can also add standard routes to an AppRouter with methods on the router.
(https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.approuter.md)
How it might look like in reality?
You can add a route on the AppRouter and define the method to handle it in either the router or controller.
MyRouter = Backbone.Marionette.AppRouter.extend({
// "someMethod" must exist at controller.someMethod
appRoutes: {
"some/route": "someMethod"
"yet/anotherRoute": "routerMethod" // app router route
},
/* standard routes can be mixed with appRoutes/Controllers above */
routes : {
"some/otherRoute" : "someOtherMethod"
},
// method on the router
routerMethod: function() {
// ...
},
someOtherMethod : function(){
// do something here.
}
});