Could someone explain me the difference between
bootstrap(MyApp, [provide(Service1, { useClass: Service1})]);
and
bootstrap(MyApp, [Service1]);
It's exactly the same. You can use it when the token used for the provider is the class itself. If you watnt to provide something else behind the provider token, you can use the provide function with useClass, useValue, useExisting or useFactory.
Here are some samples that can interest you:
Angular 2 - How to get Observable.throw globally
Inject all Services that implement some Interface
You could also have a look at the documentation of the Provider class:
https://angular.io/docs/ts/latest/api/core/Provider-class.html
There isn't really a difference.
Using this version
bootstrap(MyApp, [provide(Service1, { useClass: Service1})]);
only makes sense when the classes differ, like
bootstrap(MyApp, [provide(XHRBackend, { useClass: MockBackend})]);
to pass a MockBackend when an XHRBackend is requested (is the type of the constructor parameter.
constructor(private backend:XHRBackend) {}
would get a MockBackend instance passed in.
If you just want to pass Service1 when Service1 is requested
bootstrap(MyApp, [Service1]);
will do.
Related
I'm migrating from Dagger 2.21 and Builder is changed to Factory. How is AndroidInjector.Factory supposed to be used? I have this component
interface AppComponent : AndroidInjector<MainApplication> {
#Component.Factory
interface Factory : AndroidInjector.Factory<MainApplication> {
fun create(#BindsInstance emailId: String) : AppComponent
}
}
But it fails with "error: #Component.Factory types must have exactly one abstract method. Already found: create(T)".
AndroidInjector.Factory already seems to have a create which binds MainApplication instance. How am i supposed to bind another value? The only workaround i found is not to extend from AndroidInjector.Factory like this but then why have AndroidInjectory.Factory?
interface AppComponent : AndroidInjector<MainApplication> {
#Component.Factory
interface Factory {
fun create(#BindsInstance instance: MainApplication,
#BindsInstance emailId: String) : AppComponent
}
}
You don't need (and as you noticed you actually can't) to extend AndroidInjector.Factory when you have additional parameters needed to create the component.
You should extend AndroidInjector.Factory when you are using dagger-android to inject dependencies into android components using AndroidInjection.inject(). To make this injection possible you need to follow some rules, in particular your component's factory should extend AndroidInjector.Factory.
AndroidInjector.Factory defines AndroidInjector<T> create(#BindsInstance T instance), which will be used by dagger-android to instantiate this subcomponent, so you can't add any additional parameters.
Update:
Dagger and dagger-android are two different libraries. Dagger is a general DI framework, it does not contain any android-specific code. Component.Factory comes from dagger itself and you are free to add a method with any number of parameters, which will be used to create your subcomponent.
Dagger-android in its turn is an android-specific library which greatly reduces boilerplate code that you need to write by generating it. But you loose some flexibility and have to follow the structure defined by the library. Here your factory method cannot have any additional parameters and the factory should extend AndroidInjector.Factory.
Generally you can also mix both approaches in one project, but I would not recommend to do so to make your code consistent.
Hi i have 'static class' Utils with only static methods (helpers):
export class Utils {
static doSomethingAndRedirect() {
...doo something...
redirectTo->'/home'
}
}
So how redirectTo code should look like?
You have a wrong approach to the usecase you are trying to solve. Have a look at ngrx/store and ngrx/effects.
In short, you define actions and reducers which modify the state of your app. Next, you can react to different actions with different side-effects (ngrx/effects), for example in my app I have got:
Actions: LoginAction and LoginSuccessAction
Effects: when LoginSuccessAction is triggered, my effect redirects to /dashboard component
This makes for nice separation of concerns:
views display the current state and dispatch actions that change the state
actions specify what happens in the app
reducers specify what changes to state occur for different actions
effects specify what side-effects occur for certain actions
The best solution that I found in my case was just... add parameter 'router' into static function argument list:
static doSomethingAndRedirect(router) {
...doo something...
router.navigateByUrl('home'); // redirect
}
This is a kind of compromise between static helper convenience and non-static "angular way".
Lately i've been working a lot with Dagger 2 and I'm having this particular use case that I'm not able to do the way I want to for different reasons:
1) It's not possible; 2) I'm just not understanding the concepts behind scopes and components/subcomponents.
I have 3 Components: AppComponent, DBComponent, ActivityComponent.
I need to have my activity to inherit dependencies from AppComponent and DBComponent. This is my following setup:
AppComponent:
#Singleton
#Component(modules = { AppModule.class }) {
EventBus bus()
ActivityComponent plus(ActivityModule activityModule);
}
DatabaseComponent:
#Database
#Component(dependencies = AppComponent.class, modules = DatabaseModule.class) {
ActivityDependency activityDependency();
}
ActivityComponent:
#PerActivity
#Subcomponent(modules = ActivityModule.class) {
void inject(MainActivity activity);
}
When I inject bus() everything works fine but as soon as I try to inject ActivityDependency() it simply does not work. I cannot figure out why...
Please note: I've read about almost all the posts in here and outside explaining scopes, components and subcomponents and still I can't get my head wrapping around how to achieve what I wanted.
Note 2: I know one way to fix this which is to add DatabaseModule.class as a module in the AppComponent and remove DatabaseComponent from the equation. But I feel this will make AppComponent with too much information and this is not really the go to way.
inherit dependencies from AppComponent and DBComponent.
Wrong. You need to inherit dependencies from AppComponent, and the contents of the DBComponent should be a module of AppComponent.
Note 2: I know one way to fix this which is to add DatabaseModule.class as a module in the AppComponent and remove DatabaseComponent from the equation. But I feel this will make AppComponent with too much information and this is not really the go to way.
Yes, it is the go-to way if you're using scoped dependencies.
Think of dependency inheritance like the extends keyword in Java.
You cannot extend multiple classes with the same class, can you?
Similarly, you cannot extend multiple scoped components either.
So if you want your graph to provide bindings for a given scope, then your component needs to have all the modules for that given scope. And #Database isn't really a scope (think lifecycles), that's a renamed #Singleton.
I am following up the Heros tutorial from angular 2.0 section.5 services.
The documentation says its not necessary to wrap the this.heroes inside a function
constructor(private heroService: HeroService) { }
this.heroService.getHeroes().then(heroes => this.heroes = heroes);
which doesnt work. and getting error as
Error: TypeError: Cannot read property 'getHeroes' of undefined(…)
Whereas if i use onInit then it works (the completion of the section).
constructor(private heroService: HeroService) {
}
ngOnInit() {
this.getHeroes();
}
getHeroes() {
this.heroService.getHeroes().then(heroes => this.heroes = heroes);
}
Why i am getting the result only while running under ngOnInit?
My understanding is that the component class is a kind of toolbox, where you define properties and methods.
Methods will then respond to Angular hooks - like ngAfterViewInit or ngOnInit - or to events, like click().
Sometimes components need to load data when they are instanciated, in which case you can use ngOnInit or constructor to call your loading method.
You do not directly call methods in your class definition. I think that if you did, it could be an issue when importing a class, or when extending a class.
You don't want the class to go fetch your data each time you import your class; rather, you want to have complete control over when your data will be imported.
Here are the best practices for Angular 2
I am new to OSGi and came across several examples about OSGi services.
For example:
import org.osgi.framework.*;
import org.osgi.service.log.*;
public class MyActivator implements BundleActivator {
public void start(BundleContext context) throws Exception {
ServiceReference logRef =
context.getServiceReference(LogService.class.getName());
}
}
My question is, why do you use
getServiceReference(LogService.class.getName())
instead of
getServiceReference("LogService")
If you use LogService.class.getName() you have to import the Interface. This also means that you have to import the package org.osgi.services.log in your MANIFEST.MF.
Isn't that completely counterproductive if you want to reduce dependencies to push loose coupling? As far as I know one advantage of services is that the service consumer doesn't have to know the service publisher. But if you have to import one specific Interface you clearly have to know who's providing it. By only using a string like "LogService" you would not have to know that the Interface is provided by org.osgi.services.log.LogService.
What am I missing here?
Looks like you've confused implementation and interface
Using the actual interface for the name (and importing the interface , which you'll end up doing anyway) reenforces the interface contract that services are designed around. You don't care about the implemenation of a LogService but you do care about the interface. Every LogService will need to implement the same interface, hence your use of the interface to get the service. For all you know the LogService is really a wrapper around SLF4J provided by some other bundle. All you see is the interface. That's the loose coupling you're looking for. You don't have to ship the interface with every implementation. Leave the interface it's own bundle and have multiple implementations of that interface.
Side note: ServiceTracker is usually easier to use, give it a try!
Added benefits: Using the interface get the class name avoids spelling mistakes, excessive string literals, and makes refactoring much easier.
After you've gotten the ServiceReference, your next couple lines will likely involve this:
Object logSvc = content.getService(logRef)
// What can you do with logSvc now?!? It's an object, mostly useless
// Cast to the interface ... YES! Now you need to import it!
LogSerivce logger = (LogService)logSvc;
logger.log(LogService.LOG_INFO, "Interfaces are a contract between implementation and consumer/user");
If you use the LogService, you're coupled to it anyway. If you write middleware you likely get the name parameterized through some XML file or via an API. And yes, "LogService" will fail terribly, you need to use the fully qualified name: "org.osgi.service.log.LogService". Main reason to use the LogService.class.getName() pattern is to get correct renaming when you refactor your code and minimize spelling errors. The next OSGi API will very likely have:
ServiceReference<S> getServiceReference(Class<S> type)
calls to increase type safety.
Anyway, I would never use these low level API unless you develop middleware. If you actually depend on a concrete class DS is infinitely simpler, and even more when you use it with the bnd annotations (http://enroute.osgi.org/doc/217-ds.html).
#Component
class Xyz implements SomeService {
LogService log;
#Reference
void setLog( LogService log) { this.log = log; }
public void foo() { ... someservice ... }
}
If you develop middleware you get the service classes usually without knowing the actual class, via a string or class object. The OSGi API based on strings is used in those cases because it allows us to be more lazy by not creating a class loader until the last moment in time. I think the biggest mistake we made in OSGi 12 years ago is not to include the DS concepts in the core ... :-(
You cannot use value "LogService"
as a class name to get ServiceReference, because you have to use fully qualified class name
"org.osgi.services.log.LogService".
If you import package this way:
org.osgi.services.log;resolution:=optional
and you use ServiceTracker to track services in BundleActivator.start() method I suggest to use "org.osgi.services.log.LogService" instead of LogService.class.getName() on ServiceTracker initializazion. In this case you'll not get NoClassDefFoundError/ClassNotFountException on bundle start.
As basszero mentioned you should consider to use ServiceTracker. It is fairly easy to use and also supports a much better programming pattern. You must never assume that a ServiceReference you got sometime in the past is still valid. The service the ServiceReference points to might have gone away. The ServiceTracker will automatically notify you when a service is registered or unregistered.