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/
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!
using ES6 in my controller MyController I make an http request to retrieve a webapi json data.. works perfectly fine until..
I want to take this call and put it inside a service or a factory file outside of this controller file. I am not able to do so.. can someone guide me with this?
I have an app file that imports my controllers and other components like this
import "babel-polyfill";
import myController from "controllers";
import myFactory from "factories";
(function() {
'use strict';
config().ready.then(app => {
app.mod
.factory('myFactory', myFactory).controller('my ....
I tried to create a factory like so:
export default class myFactory{
constructor($http) {
this.$http = $http;
}
myData() {
$http.get("/source").success(function(data) {
vm.myData = data;
vm.view.dataTable = data
}).error(...);
}
}
from my controller I tried calling it:
import myFactory from "factory";
export default class myController{
constructor($http, $mdDialog, $mdToast) {
let getMyData = new myFactory;
getMyData.myData();
var vm = this;
vm.myJsonDataFromFactory .....
}
I tried to import the class to my app and then to my controller file.. none worked.
error at this point is: Error: _factory.myFactory is not a constructor
So I am used to using factories & services in Angular.
I am reading through the Angular2 docs and I don't see any equivalent of a factory. What is the equivalent for Angular2?
Factories, services, constants and values are all gone in Angular2. Angular2 is radically and fundamentally different from the classic Angular. In Angular2, the core concepts are
components
dependency injection
binding
The idea of services, factories, providers and constants has been criticized in Angular 1. It was difficult to choose between one. Removing them simplifies things a bit.
In the original Angular, you would define a service like so
app.service('BookService', ['$http', '$q', BookService]);
function BookService($http, $q){
var self = this;
var cachedBooks;
self.getBooks = function(){
if (cachedBooks) {
return $q.when(cachedBooks);
}
return $http.get('/books').then(function(response){
cachedBooks = response.data.books;
return cachedBooks;
})
}
}
Angular2 significantly leverages ES6 syntax to make the code more readable and easier to understand.
One new keyword in ES6 is class, which can be thought of as a service.
ES6 classes are a simple sugar over the prototype-based OO pattern. Having a single convenient declarative form makes class patterns easier to use, and encourages interoperability. Classes support prototype-based inheritance, super calls, instance and static methods and constructors.
Here's how that same code might look in Angular2
import {HttpService, Promise} from '../Angular/Angular2';
export class BookService{
$http, $q, cachedBooks;
constructor($http: HttpService, $q: Promise) {
this.$http = $http;
this.$q = $q
}
getBooks() {
if (this.cachedBooks) {
return this.$q.when(this.cachedBooks);
}
return this.$http.get('/books').then(function(data) {
this.cachedBooks = data.books;
return this.cachedBooks;
})
}
}
#Richard Hamilton's answer is appreciated and in addition to that there are few points to note.
For Factories,Service, and etc, in Angular2 we have service (or shared service). we have to make our service Injectable in order to use it.
NOTE: This code belongs to beta version and not RC.
import {Component, Injectable,Input,Output,EventEmitter} from 'angular2/core'
import {Router} from 'angular2/router';
import {Http} from 'angular2/http';
export interface ImyInterface {
show:boolean;
}
#Injectable() <---------------------------- Very Important
export class sharedService { <----------------- Service Name
showhide:ImyInterface={show:true};
constructor(http:Http;router:Router)
{
this.http=http;
}
change(){
this.showhide.show=!this.showhide.show;
}
}
If I want to use everywhere in my app, then I have to inject this service in bootstrap function like this,
bootstrap(App, [HTTP_PROVIDERS,sharedService <--------Name Injection
ROUTER_PROVIDERS,bind(APP_BASE_HREF).toValue(location.pathname)
]);
This way it creates single instance of your service. If you don't want to go with single instance, what you can do is - you can use Providers:[sharedService] metadata in you #component decorator.
Then, use it in your one of components like this,
export class TheContent {
constructor(private ss: sharedService) { <--------Injection dependency of your newly created service
console.log("content started");
}
showhide() {
this.ss.change(); <----- usage
}
}
Check working example here
I don't know what factories do exactly in Angular1 but in Angular2 there is useFactory:
{
provide: SomeClass,
useFactory: (dep1, dep2) => (x) => new SomeClassImpl(x, dep1, dep2),
deps: [Dep1, Dep2]
}
to provide your own instance construction logic if the default doesn't match your needs.
You can also inject a factory to create new instances yourself:
/* deprecated or removed depending on the Angular version you are using */
provide(SomeClass, {
useFactory: (dep1, dep2) => {
(x) => new SomeClassImpl(x, dep1, dep2),
},
deps: [Dep1, Dep2]
})
constructor(#Inject(SomeClass) someClassFactory: any) {
let newSomeClass = someClassFactory(1);
}
Argument x must have type assignment, otherwise angular doesn't know how to deal with it.
class SomeClassImpl {
constructor(x: number, dep1: Dep1, dep2: Dep2){}
}
If you need a new instance of a service in some component you need to provide it in that component like this:
#Component({
selector: 'hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})
This will generate a new instance of the HereService as a factory does.
I've got a pretty serious problem. I'm trying to make steps toward ES6 imports and TypeScript in my Angular 1 application. But with angular injection many ES6 imports go unused. Here is an example:
Service-
export class MyService {
public doStuff() {}
}
Controller-
import {MyService} from './service';
export class MyController {
public constructor(private MyService: MyService) {MyService.doStuff();}
}
Note it does not matter if I rename the import using as.
The problem here is that the compiler doesn't think the MyService import is being used! So the resulting compiled systemjs code does not include it-
System.register('myController', [], function() { ... });
To get around this I could make the methods on MyService static and never inject it using angular. Ex:
import {MyService} from './service';
export class MyController {
public constructor() {MyService.doStuff();}
}
But we don't have the time to do that. We are trying to do this refactor in steps, and while that's the ultimate goal, we don't have time for that at the moment.
How do I force systemjs to include these?
From the TypeScript Handbook
Import a module for side-effects only
Though not recommended practice, some modules set up some global state that can be used by other modules. These modules may not have any exports, or the consumer is not interested in any of their exports. To import these modules, use:
import "./my-module.js";
The correct way to handle this is to register the service with the angular.service before application startup. TypeScript is eliding the import because it is only used in type position, not in value position. This is not specific to "module": "system", but applies to all external module targets.
Here is what I have used successfully in a number of production apps
my-service.ts
export class MyService {
doStuff() {}
}
my-controller.ts
import {MyService} from './service';
export class MyController {
static $inject = ['MyService'];
constructor(private myService: MyService) {
myService.doStuff();
}
}
my-app.ts
import angular from 'angular';
import {MyController} from './my-controller';
import {MyService} from './my-service';
const app = angular.module('app', []);
app.controller({ MyController });
app.service({ MyService });
export function bootstrap(target: Document | Element) {
angular.bootstrap(target, ['app'], { ngStrictDi: true });
}
To explain, the service itself needs to be registered with an angular module in order to be injected in the first place, so the elided import is a non issue since the registration code, shown in my-app.ts, uses MyService in value position when passing it as an argument to angular.service.
A nice pattern is to register all of the services that comprise a certain set of functionality in a single place. The logical place to do this is in the file containing the angular module which will hold the services.
Also note the static $inject = ['MyService']; this ensures your controller code is minification safe while allowing you to co-locate the DI annotation with the constructor that requires it.
I have found this pattern scales very well.
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