I have this component
#Component({
templateUrl: './app/component/template/actualstate.template.html',
styleUrls: ['./app/component/style/actualstate.style.css'],
pipes: [MomentPipe, CapitalizePipe]
})
export class ActualStateComponent implements OnInit {
public room: Room;
constructor(private roomService: RoomService) {
roomService.roomSelected$.subscribe(room => this.onRoomSelected(room));
}
onRoomSelected(room: Room) {
this.room = room;
console.log("room", room);
}
}
and this other component
#Component({
templateUrl: './src/admin/template/admin.template.html',
styleUrls: ['./src/admin/style/admin.style.css'],
providers: [UserService]
})
export class AdminComponent{
constructor ( private roomService: RoomService) {
}
onClick () {
this.roomService.selectRoom("","");
this.router.navigate(['ActualState']);
}
}
}
, this service :
#Injectable()
export class RoomService {
private route_room = "public/mock/room.json";
public roomSelected$: EventEmitter<Room>;
constructor (private http: Http) {
this.roomSelected$ = new EventEmitter();
}
public selectRoom (subdomain: string, id: string) {
// pick the right room
let room = ...
this.roomSelected$.emit(room);
}
private handleError (error: Response) {
return Observable.throw(error.json().error || 'Server error');
}
}
And this template :
<div class="actual-state" *ngIf="room">
<h3>Salle {{ room.name }}
</h3>
</div>
The purpose is :
Admin component (user click on some button)
-> Listener OnClick calls a method on service roomService
-> roomService emit an event (that is public)
-> appComponent listen to this event (.subscribe)
I have no clue why this is not working. The <h3> is never showing .. even though the console.log(room) display something in the console...
How does this data binding working ? Because it just looks like data are not two-way bound
...
EDIT : i understood the problem, it was related to the routing i made. in fact i did'nt understand the fact that component of a route is destroyed when you change the route
I guess you need to subscribe
return this.http.get(this.route_room)
.map(res => res.json())
.do(data => {
this.roomSelected$.emit(data);
})
.subscribe(value => {})
.catch(this.handleError);
Related
How can we share data between two components - both are completely separate components? (which are not in a child-parent relationship)
I want to show my registration component's variable 'totalReg' value in my header component. Both files are below.
This is my reg.component.ts
import { Component, Output } from '#angular/core';
import { UserService } from '../services/reg.service';
import { VERSION } from '#angular/core';
#Component({
templateUrl: 'reg.component.html'
})
export class RegComponent {
constructor(
private userService: UserService,
) { }
#Output() totalReg: any;
register(event: any) {
this.userService.create(event.target.username.value)
.subscribe(
data => {
this.totalReg = data['data'].userId;
console.log(this.totalReg); // Navigate to the
listing aftr registration done successfully
},
error => {
console.log(error);
});
}
}
This is my header.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
This is html of my header component header.component.html
<div class="container">
<mat-toolbar>
<ul class="nav navbar-nav">
<li><a [routerLink]="['/login']">Login</a></li>
<li><a [routerLink]="['/reg']">Registration</a>
</li>
<li><a [routerLink]="['/users']">All Users</a>
</li>
</ul>
</mat-toolbar>
<span>{{totalReg}}</span>
</div>
header component should show the value of totalReg .
you can do this with help of service class.
you are already using the UserService in RegComponent , so use the same service in the HeaderComponent to get the data.
HeaderComponent.ts
export class HeaderComponent implements OnInit {
totalReg: any;
constructor(private service : UserService) { }
ngOnInit() {
this.totalReg = this.service.totalRg;
}
}
RegComponent.ts
export class RegComponent {
#Output() totalReg: any;
constructor(private userService: UserService) { }
register(event: any) {
this.userService.create(event.target.username.value)
.subscribe(data => {
this.totalReg = data['data'].userId;
console.log(this.totalReg); // Navigate to the listing aftr registration done successfully
this.service.totalRg = this.totalReg;
},
error => {
console.log(error);
});
}
}
you are already using a class in service class you need add the variable as totalRg
UserService.ts
export class UserService {
totalRg:any;
constructor() { }
create(name: any) {
return ....//
}
}
I am new to angular 7 and didn't find any proper answer for similar questions posted.
I am getting Property 'subscribe' does not exist on type 'void' in angular-cli. I tried importing subscribe from rxjs but didn't find that library.
The problem is in the UpdateRecord Function!
product.component.ts code:
the code bellow is exist in compoent.ts of product
import { Component, OnInit } from '#angular/core';
import { ProductService } from 'src/app/shared/product.service';
import { NgForm } from '#angular/forms';
import { ToastrService } from 'ngx-toastr';
import { filter, map } from 'rxjs/operators';
#Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
constructor(private service : ProductService, private toastr : ToastrService) { }
ngOnInit() {
this.resetForm();
}
resetForm(form?: NgForm) {
if (form != null)
form.resetForm();
this.service.formData = {
ProductID: null,
ProductName: '',
ProductDescription: '',
Price: 0.00,
Image: '',
Qte: null
}
}
onSubmit(form: NgForm) {
if (form.value.ProductID == null)
this.insertRecord(form);
else
this.updateRecord(form);
}
insertRecord(form: NgForm) {
this.service.postProduct(form.value).subscribe(res => {
this.toastr.success('Inserted successfully', 'Product. Register');
this.resetForm(form);
this.service.refreshList();
});
}
updateRecord(form: NgForm) {
this.service.putProduct(form.value).subscribe(res => {
this.toastr.success('Updated successfully', 'Product. Update');
this.resetForm(form);
this.service.refreshList();
});
}
}
product.service.ts code :
the code bellow is exist in service file related to product
import { Injectable } from '#angular/core';
import { Product } from './product.model';
import { HttpClient } from "#angular/common/http";
#Injectable({
providedIn: 'root'
})
export class ProductService {
formData : Product
list : Product[]
readonly rootURL= 'http://localhost:50369/api'
constructor(private http : HttpClient) { }
postProduct(formData : Product){
return this.http.post(this.rootURL+'/Product', formData);
}
refreshList(){
return this.http.get(this.rootURL+'/Product')
.toPromise().then(res => this.list = res as Product[]);
}
putProduct(formData : Product){
this.http.put(this.rootURL+'/Product/'+formData.ProductID,FormData);
}
}
Thanks in advance,
I missed return :
So in putProduct function in product.service.ts is updated to be :
putProduct(formData : Product){
return this.http.put(this.rootURL+'/Product/'+formData.ProductID,FormData);
}
And it's working now!
Your HttpClient.put function seems to be incorrectly used (you are passing the class as parameter when you should be passing the object).
Look for the function updateHero() in this StackBlitz example.
/** PUT: update the hero on the server. Returns the updated hero upon success. */
updateHero (hero: Hero): Observable<Hero> {
httpOptions.headers =
httpOptions.headers.set('Authorization', 'my-new-auth-token');
return this.http.put<Hero>(this.heroesUrl, hero, httpOptions)
.pipe(
catchError(this.handleError('updateHero', hero))
);
}
================================================================
EDIT : SOLUTION After upgrading to 2.0 Final - Passing server parameters to ngModule after RC5 upgrade
==================================================================
Any way to have server parameters passed to an Angular 2 application?
i.e. I would like to use the MVC object "HttpContext.User.Identity.Name" and have it injectable anywhere in my angular 2 app.
In angular 1 this was possible using ng ".constant" and serializing .Net objects to JSON in index.cshtml.
Looks like there's a way to pass params but this doesn't work with .Net code.
Define global constants in Angular 2
//HTML - Bootstrapping
<script>
System.import('app/main').then(null, console.error.bind(console));
//I WOULD LIKE TO PASS SOME PARAMS TO APP/MAIN HERE
</script>
FINAL SOLUTION: (big thanks to Thierry)
index.cshtml:
<script>
System.import('app/main').then(
module =>
module.main(
{
name: '#User.Identity.Name',
isAuthenticated: User.Identity.IsAuthenticated.ToString().ToLowerInvariant(),
}
),
console.error.bind(console)
);
</script>
main.ts:
...
import {provide} from '#angular/core';
...
export function main(params) {
bootstrap(AppComponent,
[
provide('Name', { useValue: params.name }),
provide('IsAuthenticated', { useValue: params.isAuthenticated }),
ROUTER_PROVIDERS,
HTTP_PROVIDERS,
LoggerService,
AuthenticationService
]);
}
Usage:
import {Component, Injectable, Inject} from '#angular/core';
import {ROUTER_DIRECTIVES} from '#angular/router';
#Component({
selector: 'navbar',
templateUrl: 'app/components/header/navbar.html',
directives: [ROUTER_DIRECTIVES]
})
export class SomeComponent {
constructor(#Inject('Name') public username: string) {
}
}
An option would be to add a method in the module you import. So you can then call it to provide the object you want.
Here is a sample of the app/main module:
import {bootstrap} from '...';
import {provide} from '...';
import {AppComponent} from '...';
export function main(params) {
let userIdentityName = params.name; // for example
bootstrap(AppComponent, [
provide('userIdentityName', { useValue: userIdentityName })
]);
}
Then you can import it from your HTML main page like this:
<script>
System.import('app/main').then((module) => {
module.main({
userIdentityName: 'something from asp.net'
});
});
</script>
Update
With latest versions of Angular, you need to leverage modules this way:
export const USER_IDENTITY_NAME_TOKEN =
new InjectionToken('userIdentityName');
#NgModule({
(...)
providers: [
{
provide: USER_IDENTITY_NAME_TOKEN,
useValue: userIdentityName
}
]
})
export class MainModule() { }
thanks for info, for those using platformBrowserDynamic to boot:
main.ts:
//platformBrowserDynamic().bootstrapModule(asstModule);
export function main(appSettings: any) {
platformBrowserDynamic([{ provide: 'AppSettings', useValue: appSettings }]).bootstrapModule(asstModule);
}
With a .NET Core server, I recommend to use a the IOptions<> and a ViewComponent
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddOptions();
services.Configure<Models.EnvironmentSettings>(Configuration.GetSection("client"));
services.Configure<Models.EnvironmentSettings>(options =>
{
options.OtherSetting = "Other";
});
services.AddMvc();
}
Models/EnvironmentSettings.cs
public class EnvironmentSettings
{
public string OtherSetting { get; set; }
public string LoginUrl { get; set; }
}
appsettings.json
{
"client": {
"LoginUrl": "http://localhost:45290/Token"
}
}
Controllers/Components/BootstrapViewComponent.cs
public class BootstrapViewComponent : ViewComponent
{
private IOptions<EnvironmentSettings> environmentSettings;
public BootstrapViewComponent(
IOptions<EnvironmentSettings> environmentSettings
)
{
this.environmentSettings = environmentSettings;
}
public async Task<IViewComponentResult> InvokeAsync()
{
return View(environmentSettings.Value);
}
}
Views/Shared/Components/Bootstrap/Default.cshtml
#model YourApp.Models.EnvironmentSettings
<script>
System.import('app')
.then(function (module) {
module.main({
other: "#Model.OtherSetting",
loginUrl: "#Model.LoginUrl"
})
})
.catch(function (err) {
console.error(err);
});
</script>
Views/Shared/_Layout.cshtml
<head>
...
#await Component.InvokeAsync("Bootstrap")
</head>
main.ts
export function main(settings: any) {
platformBrowserDynamic([{ provide: 'EnvironmentSettings', useValue: settings }]).bootstrapModule(AppModule);
}
Is there a way to access a component used in a different component's dart file?
Component1.dart
#Component(
selector: 'comp1',
templateUrl: 'packages/comp1_package/Component1.html',
cssUrl: 'packages/comp1_package/Component1.css',
useShadowDom: false)
class Component1 {
Component1 get comp1ctrl => this;
Component1() {
}
void testing() {
// WANT TO CALL COMP2 printTest HERE
}
}
Component1.html
<div id="mainTab" class="maincontainer">
<comp2></comp2>
</div>
Component2.dart
#Component(
selector: 'comp2',
templateUrl: 'packages/comp2_package/Component2.html',
cssUrl: 'packages/comp2_package/Component2.css',
useShadowDom: false)
class Component2 {
Component2 get comp2ctrl => this;
Component2() {
}
void printTest() {
print("PRINTING FROM IN COMP2");
}
}
Component2.html
<h3>TEST HEADER</h3>
How can I get access to the Component2 object in Component1.dart and be able to call a method in it? Any help would be appreciated!
If I have a AngularDart Component:
#Component(selector: "my-selector",useShadowDom: false,
templateUrl: "packages/test/test.html")
class MyComponent {
MyComponent() {
...
}
...
}
How can I get the templateUrl programmatically?
I want to avoid a constructor with an Element injected. An injected Injector would be OK.
Found the answer:
#Component(selector: "my-selector", useShadowDom: false,
templateUrl: "packages/test/test.html")
class MyComponent {
Injector _injector;
MyComponent(this._injector) {
}
String get url {
DirectiveMap _directiveMap = _injector.get(DirectiveMap);
var tuples = _directiveMap['my-selector'];
//Validate.isTrue(tuples[0].directive is Component);
Component annotation = tuples[0].directive;
//_logger.info("TemplateUrl: ${annotation.templateUrl}");
return annotation.templateUrl;
}
}