- Provide them on bootstrapping if you only want one instance across the whole app
- Use component providers array to have one new instance of that service, scope-limited.
MUCH FAST, TOO EASY, WOW
/app/components/: $ ng g component my-component // Creates component
/app/components/my-component/: $ ng g component my-nested-component
Amongst others.
Great explanation about possibilities of modals deep down in presenter components. It's in React, but the concept still remains useful:
So, you have something like.
export class BufferComponent implements OnChange {
@Input() buffer: Array<string>;
ngOnChange() {
makeSparkles();
}
}
Oh, boy. Good luck detecting changes on that array. BREAKING NEWS: Angular2 per default only detects changes when reference changes... and pushing a new item on your beloved array won't do that.
Let's detect that. So, if OnChange phase doesn't detect changes... who else would do it? Let's review life cicle:
Yep, we have that DoCheck triggered during every change detection run, immediately after ngOnChanges and ngOnInit. And docs say it stands for checking WHAT ANGULAR CAN'T OR WON'T DETECT ON ITS OWN. Looks like we have a wingman.
export class BufferComponent implements DoCheck {
@Input() buffer: Array<string>;
ngDoCheck() {
doSparkles()
}
}
YAS, you got it. Sparkles everywhere on each life cycle triggered. Wait. When is a life cycle triggered then? ngDoCheck is triggered every time the input properties of a component or a directive are checked. And when they change, despite of not being detected by ngOnChanges, it's checked anyways.
BUUUUUUUUT, if we have many inputs like:
export class BufferComponent implements DoCheck {
@Input() buffer: Array<string>;
@Input() person: string;
ngDoCheck() {
doSparkles()
}
}
If person changes, doSparkles will be called even, and our expected behaviour was to sparkle all the sh*t out of the screen ONLY on buffer change.
One last step.
Add KeyPairDiffer to constructor. Generate an array differ and bound it to the components. Then check difference between this differ and buffer. Talk is cheap, let's see the code:
export class BufferComponent implements DoCheck {
@Input() buffer: Array<string>;
differ: any;
constructor(private elementRef: ElementRef, private differs: KeyValueDiffers) {
this.differ = differs.find([]).create(null);
}
ngDoCheck() {
var changes = this.differ.diff(this.buffer);
if(changes) {
doSparkles();
}
}
}
HELL YEA. Perfect. Hats off.
Two structural directive (*whatEver) on same element raises an error.
You can use ngContainer to separate elements but not reflect this separation on DOM:
<ng-container *ngIf="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</ng-container>
https://stackoverflow.com/a/39565934
You can use *ngFor for those use cases, even if it's just a single object.
@Component({
selector: 'image-holder',
template: `
<div class="carousel-image">
<img [src]="image" *ngFor="let image of [image]" [@slideInRight]/>
<span>{{ text }}</span>
</div>
`,
styleUrls: ['../greenscreen.scss'],
animations: [
trigger(
'slideInRight',
[
transition(
':enter', [
style({transform: 'translateX(100%)', opacity: 0}),
animate('500ms', style({transform: 'translateX(0)', opacity: 1}))
]
),
transition(
':leave', [
style({transform: 'translateX(0)', 'opacity': 1}),
animate('500ms', style({transform: 'translateX(-100%)', opacity: 0}))
]
)
])
]
})
export class ImageHolderComponent {
@Input()
image: string;
@Input()
text: string;
https://stackoverflow.com/a/43978066/1306660
On TestBed include the following import:
import {RouterTestingModule} from '@angular/router/testing';
[...]
TestBed.configureTestingModule({
imports: [RouterTestingModule], <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
declarations: [ ChooseTypePageComponent ],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
})
Gently import RouterTestingModule:
import { RouterTestingModule } from '@angular/router/testing';
And include it on TestBed:
TestBed.configureTestingModule({
imports: [
MyModule,
RouterTestingModule.withRoutes([]),
],
}).compileComponents();
So, got some parameters through URL? Gettin' them on ngOnInit? Let's mock 'em all! As for this case, I expect you to have smth like:
this.sub = this.activatedRoute.params.subscribe(params => {
this.challengueId = +params['challengueId']
this.challengue = this.challenguesService.getChallengueById(this.challengueId);
});
Yep, first override ActivatedRoute provider on the component annotations:
providers: [
{ provide: ActivatedRoute, useValue: { 'params': Observable.from([{ 'challengueId': 1 }]) }}
]
This is breaking your code. Of course, where is that Observable coming from? Import it:
import { Observable } from 'rxjs/Rx';
We are subscribing to variable ([...]params.subscribe(params=>[...]) so one can not just return a variable, we make 'em observable. That's it.
You may have probably included the service you want to fake inside
[...] providers: [] [...]
If so, Angular says that providers annotated on components are the ones, the highest level, jetset, nothing to f*ck with. You'll probably want to refactor this, in case you don't need new instances (see "ng2 services, singletons or not?") OOOOOOOOOR:
TestBed.overrideComponent(YourComponent, {
set: {
providers: [{ provide: YourService, useClass: YourServiceStub }]
}
})
NAILED.
Check if you imported CUSTOM_ELEMENTS_SCHEMA from anything else than @angular/core.
- Force installs in consumer app => dependencies
- Provided by library => bundledDependencies
- Require manual install by consumer => peerDependencies
- Invisible to consumer, not included in library => devDependencies
Share + Replay(n):
- share => turns observable into a multicast. When subscribed to an observable with a pipe, prevents running the pipe for each subscription.
- replay => emits the last (n) to late subscribers.
When to use:
- Pipes with unwanted to be repeated side-effects
- Complex calculations on pipe