My web application has multiple filters that should be represented in the current Url so that users can simply copy/bookmark the current page to get it back later.
In angular1 I used $location.search(name, value) to simply set seach params on change. Now I want to get something similar in angular2.
Or is it wrong?
I think you must use the router inside Angular2. code example:
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {ProfileComponent} from './profile.component';
#Component({
selector: 'my-app',
template: `
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
})
#RouteConfig([
{path: '/profile/:id', name: 'Profile', component: ProfileComponent}
])
export class AppComponent {
}
The :id is a route parameter and you can do an URL like that:
/profile/2 and 2 is the value of the id parameter.
You could find more detail in the Angular2 doc : router doc
Related
I am trying to call HTML file into TS file, but I see file not found error.
#Component({
selector: 'app/jsonData.ts',
templateUrl: 'src/app/jsonData.html',
})
export class AppComponent {
title = 'Angular';
}
Please explain
#Component({
selector: 'my-app',
templateUrl: './jsonData.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'Angular';
}
The selector should not contain the path because the selector is going to be used like this: <my-app></my-app> in some HTML template/file.
And coming to the templateUrl, it takes relative path to the HTML template. Since both the component and the template URL you're going to use are in the same folder, you can use ./ followed by the required file name.
That being said, it is better to name your files appropriately. app.component.ts, app.component.html, app.component.css
Hope this helps!
I have a hybrid angular-cli that roughly follows Victor Savkin's Lazy Loaded AngularJS guide. AngularJS is bootstraped in the constructor of a LazyLoaded Angular module. The main difference between my app and the guide is that I am trying to wrap the <ui-view> directive inside of some Angular components. Because of how my layout is structured the <ui-view> element will not be available when AngularJS is bootstrapped and may be added or removed at any time.
import { Component, Directive, ElementRef, Injector } from '#angular/core';
import { UpgradeComponent } from '#angular/upgrade/static';
import * as angular from 'angular';
#Component({
template: `
<layout-wrapper>
<my-toolbar></my-toolbar>
<layout-contents>
<ng2-ui-view>
<h3 class="text-center">AngularJS page not loaded</h3>
</ng2-ui-view>
</layout-contents>
</layout-wrapper>
`,
})
export class LegacyOutputComponent { }
#Directive({selector: 'ng2-ui-view'})
export class UpgradedUiViewComponent extends UpgradeComponent {
constructor(ref: ElementRef, inj: Injector) {
super('uiViewWrapper', ref, inj);
}
}
export const routerPatchModule = 'arcs.router.patch';
// We need to define a wrapper for ui-view because we can only upgrade
// components with only one definition. uiView cannot be automatically
// upgraded because its definition is too complex
angular.module(routerPatchModule, ['ui.router'])
.component('uiViewWrapper', { template: '<ui-view></ui-view>'})
When I run the code a Error: No provider for $scope! error is thrown. Checking the stack trace I can see that it is thrown in the UpgradeComponent super class. The injector tries to get $scope and
Alternative is to let Angular know that it needs to provide the $scope.
import { Injector } from '#angular/core';
// allow $scope to be provided to ng1
export const ScopeProvider = {
deps: ['$injector'],
provide: '$scope',
useFactory: (injector: Injector) => injector.get('$rootScope').$new(),
};
#Directive({
providers: [ ScopeProvider ],
selector: 'ng2-ui-view',
})
export class UpgradedUiViewComponent extends UpgradeComponent {
constructor(ref: ElementRef, inj: Injector) {
super('uiViewWrapper', ref, inj);
}
}
This setup will not work. AngularJS needs to be able to load in the root of your application in order for the scope to be defined correctly.
A better way to approach this problem is to use the <div ui-view> directive in the root of your application (as in the upgrade guide) and then to downgrade a layout component from Angular into AngularJS to wrap your content.
I don't know how to do wildcard path routing in an app that's half-upgraded from AngularJS to ng2.
In general, you mix both kinds of routing like this:
The first step to have a dual router setup is to add an Angular root
component containing one outlet for each router. AngularJS will use
ng-view, and Angular will use router-outlet. When one is using it's
router, the other outlet will be empty.
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<router-outlet></router-outlet>
<div ng-view></div>
`,
})
export class AppComponent { }
https://angular.io/docs/ts/latest/guide/upgrade.html#!#dividing-routes-between-angular-and-angularjs
In Angular 2 you can specify a wildcard path like this:
{ path: '**', component: PageNotFoundComponent }
In AngularJS you can have a wildcard path like this:
$routeProvider
.otherwise({
template: '<page-not-found></page-not-found>',
});
When I put everything together and a path isn't handled, how do avoid both routers from emitting <page-not-found> ?
I can confirm that <div ng-view></div> does work in the angular 2 AppComponent component if everything else is set up right. (Add AppComponent to AppModule's bootstrap array).
Use HybridUrlHandlingStrategy to prevent Angular from throwing an error when an ng1 route is requested.
Add dummy routes with empty ("") templates to prevent ng1 from rendering 404 page when an ng2 page is requested:
$routeProvider
.when('/some/ng1/path', {template: '<something></something>'})
.when('/some/ng2/path', {template: ''}) // ng2 route
.otherwise({template: '<page-not-found></page-not-found>'});
I am using typescript with angular 1.5 component. And I have a custom designed decorator where I send template via require. It works except I get a tslint warning. (I don't want to turn off this rule)
require() style import is forbidden
Here is my component
import './main.template.html';
const app: ng.IModule = angular.module('app');
#Component(app, {
selector: 'mainComponent',
controllerAs: 'ctrl',
styleUrls: '',
template: require('./main.template.html')
})
class MainComponent extends BaseComponent {
constructor() {
super();
}
}
Here is my decorator
export const Component = function(module: ng.IModule, options: {
selector: string,
controllerAs?: string,
styleUrls?: string,
template?: string,
templateUrl?: string
}) {
return (controller: Function) => {
module.component(options.selector, angular.extend(options, { controller: controller }));
};
};
I have tried to pass templateUrl instead of template and i get run time error of file not found.
I have also tried to import template as variable and it gives compile time error and looks like it's not supported.
import mytemplate: string from './main.template.html';
I am using webpack. Hence, can't use absolute path from the root.
Do you have any idea how to import template in typescript without using require.
For templateUrl error , check your reference and directory structure.
Or , insert html data inside template :-
#Component(app, {
selector: 'mainComponent',
controllerAs: 'ctrl',
styleUrls: '',
template: `<div>//content
</div>`
})
I tried to search but I didn't get the answer.
I can't realize when I must define "providers" section in #Component definition.
I looked over examples.
half of them use
1)
import { Component, blah-blah} from '#angular/core';
import { SomeService } from './some.service';
#Component({
selector: 'example-selector',
providers: [SomeService ],
.....
constructor(public someService : SomeService ,
2) but half of them WITHOUT "providers" section!
import { Component, blah-blah} from '#angular/core';
import { SomeService } from './some.service';
#Component({
selector: 'example-selector',
.....
constructor(public someService : SomeService ,
===
so, I am confused: when I need that section and when I don't?
I believe Maxouhell gave the right answer in another question:
If you provide your service inside your component, it will be local to it. So if you have two instance of your component, you will have two instance of your service.
Now if you provide your service inside your module, it will be global and if you have two instance of your component, they will share the same instance of the service.
I believe it has to do with at what level you declare your providers. You must declare a provider for each component or service that you use
For example in my app, I have a service that I provide in main.ts which is then available to any component without having to indicate the provider there.
bootstrap(AppComponent,
[
APP_ROUTER_PROVIDER,
HTTP_PROVIDERS,
SettingsService,
disableDeprecatedForms(),
provideForms()
]).catch((err: any) => console.error(err));
#Component({
selector: 'kg-Settings ',
templateUrl: './app/components/settings/settings.component.html',
styleUrls: ['./app/components/settings/settings.component.css'],
directives: [ROUTER_DIRECTIVES, REACTIVE_FORM_DIRECTIVES]
})
However, if I want to inject a component into another component and it has not been previously provided for at a higher level in the app tree,
#Component({
selector: 'k-Calculator ',
templateUrl: './app/components/calculator/calculator.component.html',
styleUrls: ['./app/components/calculator/calculator.component.css'],
directives: [ROUTER_DIRECTIVES, REACTIVE_FORM_DIRECTIVES, Panel, Dropdown, SelectButton, Button],
providers: [CalculationService]
})
You need provider section whenever you need to use a service in that component.
Item #1, defined the provider within the component.
Item #2, (might) defined the provider in app.component.ts (Please check the main file)