RouterConfiguration and Router undefined in aurelia - import

I am very new to Aurelia and just trying to apply navigation to my project.Though i import aurelia-router still it says RouterConfiguration and Router are undefined in constructor
import {Todo} from './ToDo/todo';
import {RouterConfiguration, Router} from 'aurelia-router';
export class App {
heading = "Todos";
todos: Todo[] = [];
todoDescription = '';
router :any;
list: any[];
constructor(RouterConfiguration: RouterConfiguration, Router: Router) {
this.todos = [];
this.configureRouter(RouterConfiguration, Router);
//console.log("klist", this.list);
}
//config.map() adds route(s) to the router. Although only route, name,
//moduleId, href and nav are shown above there are other properties that can be included in a route.
//The class name for each route is
configureRouter(config: RouterConfiguration, router: Router): void {
this.router = router;
config.title = 'Aurelia';
config.map([
{ route: '', name: 'home', moduleId: 'home/home', nav: true, title: 'Home' },
{ route: 'users', name: 'users', moduleId: './Friends/Friends', nav: true },
//{ route: 'users/:id/detail', name: 'userDetail', moduleId: 'users/detail' },
//{ route: 'files/*path', name: 'files', moduleId: 'files/index', href: '#files', nav: 0 }
]);
}
addTodo() {
if (this.todoDescription) {
this.todos.push(new Todo(this.todoDescription));
// this.todoDescription = '';
}
}
}

By convention, Aurelia looks in the initial class that loads (App) for the configureRouter() function and executes it. This means, you do not have to inject anything in the constructor.
It looks like you've simply added too much. I think fixing your sample seems to be as easy as removing some stuff, like so:
import { Todo } from './ToDo/todo';
import { RouterConfiguration, Router } from 'aurelia-router';
export class App {
heading = "Todos";
todos: Todo[] = [];
todoDescription = '';
list: any[];
constructor() {
// note: removed routing here entirely (you don't need it)
// also, you've already declared this.todos above, so no need to do it here again
}
configureRouter(config : RouterConfiguration, router : Router): void {
this.router = router;
config.title = 'Aurelia';
config.map([
{ route: '', name: 'home', moduleId: 'home/home', nav: true, title: 'Home' },
{ route: 'users', name: 'users', moduleId: './Friends/Friends', nav: true }
]);
}
addTodo() {
// removed this for brevity
}
}
This should resolve your 'undefined' errors on Router and RouteConfiguration. As an additional note, don't forget to add the <router-view> to your html template as well. Otherwise, you'll get no errors but the views won't show up either:
<template>
<div class="content">
<router-view></router-view>
</div>
</template>
Great documentation on this can be found at the Aurelia Docs - Routing.

Related

Ionic 4. Alternative to NavParams

I am using ionic 4. It does not accept to receive data using navparams.
Here is my sender page method:
//private route:Router
gotoFinalView(intent) {
this.route.navigateByUrl(`${intent}`, this.destination);
}
Receiver page line;
//private navParams:NavParams
this.destination = navParams.data;
What is the right approach to doing this in ionic 4. I am also uncertain whether gotoFinalView method is valid.
This is how I solved my problem:
I created a Service with a setter and getter methods as;
import { Injectable } from "#angular/core";
#Injectable({
providedIn: "root"
})
export class MasterDetailService {
private destn: any;
constructor() {}
public setDestn(destn) {
this.destn = destn;
}
getDestn() {
return this.destn;
}
}
Injected the Service and NavController in the first page and used it as;
gotoFinalView(destn) {
this.masterDetailService.setDestn(destn);
this.navCtrl.navigateForward("destn-page");
}
Extracted the data at the final page by;
constructor(
private masterDetailService: MasterDetailService
) {
this.destination = this.masterDetailService.getDestn();
}
This is the efficient way to solve your problem
user Angular Routers concepts in your application.
just declare your router like the following
Your app routing module like the following
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import {ViewComponent} from "./crud/view/view.component";
import {CreateComponent} from "./crud/create/create.component";
import {UpdateComponent} from "./crud/update/update.component";
import {ReadComponent} from "./crud/read/read.component";
const routes: Routes = [
{path: '', component: ViewComponent},
{path: 'create', component: CreateComponent},
{path: 'update/:id', component: UpdateComponent},
{path: 'view/:id', component: ReadComponent}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
:id is the parameter what i want to send to that page.
this.router.navigate([link + '/' + id]);
share your parameter like this in your first page.
In your second page inject the activated route using DI(Dependency Injection)
constructor(private actRoute: ActivatedRoute)
Then Get your parameters using the following code
this.productID = this.actRoute.snapshot.params['id'];
This is the simple way. You can send multiple parameter at a time.
{path: 'update/:id/:name/:price', component: UpdateComponent}
and get those parameters like the following
this.productID = this.actRoute.snapshot.params['id'];
this.productName = this.actRoute.snapshot.params['name'];
this.productPrice = this.actRoute.snapshot.params['price'];
While Routing you can write like this:
this.router.navigate(["/payment-details",{
prev_vehicle_type: this.vehicle_type,
prev_amt: this.amt,
prev_journey:this.whichj
}]);
To get this parameters on the next page you can write:
constructor(
public router: Router,
public activateroute: ActivatedRoute){
this.activateroute.params.subscribe((data: any) => {
console.log(data);
this.vehicle_type = data.prev_vehicle_type;
this.amt = data.prev_amt;
this.whichj = data.prev_journey;
});
}
ionic 4 navigation with params
sender page
1. import the following
import {NavController} from '#ionic/angular';
import { NavigationExtras } from '#angular/router';
constructor(private navCtrl:NavController)
sender page
gotonextPage()
gotonextPage()
{
let navigationExtras: NavigationExtras = {
state: {
user: 'name',
parms:Params
}
};
this.navCtrl.navigateForward('pageurl',navigationExtras);
}
4.Receiver Page
import { ActivatedRoute, Router } from '#angular/router';
constructor( private route: ActivatedRoute, private router: Router)
{
this.route.queryParams.subscribe(params => {
if (this.router.getCurrentNavigation().extras.state) {
this.navParams = this.router.getCurrentNavigation().extras.state.parms;
}});
}
Send data with Router service and extract with global variable, history
//sender component
// private router: Router
nextPage() {
this.router.navigate(['history'],
{ state: [{ name: "covid-19", origin: "china" },{ name: "ebola", origin: "us" }] }
)
}
//receiver page
ngOnInit() {
let data = history.state;
console.log("data-->",data);
// ** data**
//0:{name: "covid-19", origin: "china"} 1: {name: "ebola", origin: "us"} navigationId: 2
}
The item, icon and title variables you want to send should be written in the state in this way.
this.nav.navigateForward('/myUrl', {
state: {
'items': this.substances,
'icon': ICONS.substance,
'title': 'Etken Maddeler'
}
});
We take incoming variables this way.
//receive
constructor(
protected route: ActivatedRoute,
protected router: Router,
) {
this.selectedItem = null;
this.route.paramMap.subscribe(params => {
let st = this.router.getCurrentNavigation().extras.state;
if (st) {
this.selectedItem = st.items;
}
});
}
Very very simply, you can do something like this:
In the "calling screen" :
this.router.navigate(['url', {model: JSON.stringify(myCustomObject)}])
In the "called screen" :
this.myvar = JSON.parse(this.activatedRoute.snapshot.paramMap.get('model')
Et voilà !
//in home.ts
import{ Router,ActivatedRoute, NavigationExtras } from '#angular/router';
getProductStatics(productObject : any) {
var object1 = {
id: productObject,
}
const navigationExtras: NavigationExtras = {state : {object:
JSON.stringify(object1)}};
this.router.navigate(["/product-statics"], navigationExtras);
}
//in product-statics.ts
import{ Router,ActivatedRoute,NavigationExtras } from '#angular/router';
if(self.router.getCurrentNavigation().extras.state) {
var object1
= this.router.getCurrentNavigation().extras.state.object;
var object = JSON.parse(object1);
var newObjectData = object.id;
}

Dynamic Forms FormArray angular 2

I followed the Todd Motto article about dynamic form with angular 2 (https://toddmotto.com/angular-dynamic-components-forms).
Every thing works perfectly.
But I have a project, project for pleasure, where I try to pass formatted array to config, this is the data :
travel = [
{
type: 'input',
label: 'From',
placeholder: 'From',
name: 'from',
},
{
type: 'input',
label: 'To',
placeholder: 'To',
name: 'to'
}
];
travellers = [
{
type: 'input',
label: 'Name',
placeholder: 'name',
name: 'name',
}
]
config = {
travel: [
{
...this.travel
},
{
...this.travel
}
],
travellers: [
{
...this.travellers
}
]
};
Here the call of dynamic-form component :
<dynamic-form [config]="config" (submitted)="formSubmitted($event)"></dynamic-form>
This is the dynamic-form component :
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
import { FormGroup, FormArray, FormControl, FormBuilder } from '#angular/forms';
import * as _ from 'lodash';
#Component({
selector: 'builder-form',
templateUrl: './builder-form.component.html',
styleUrls: ['./builder-form.component.css']
})
export class BuilderFormComponent implements OnInit {
#Input()
config: any[] = [];
#Output()
submitted: EventEmitter<any> = new EventEmitter<any>();
form: FormGroup;
objectKeys = Object.keys;
constructor (private fb: FormBuilder) { }
ngOnInit() {
this.form = this.createGroup();
}
createGroup () {
const group = this.fb.group({});
let groupArray = Object.keys(this.config);
let control;
groupArray.forEach((value, i) => {
group.addControl(value, this.fb.array([]));
control = group.controls[value] as FormArray;
_.map(this.config[value], (val, key) => {
// object is the travel { from, to } and the traveller { name }
let object = {}
_.map(val, (v, k) => {
Object.assign(object, {[v.name]: null})
});
control.push(this.fb.group(object, this.fb.control(null)));
});
});
return group;
}
}
And I get this :
FormGroup {
...
controls {
travel: FormArray {
...
controls: [
0: FormGroup {
controls: { form: FormControl, to: FormControl }
},
1: FormGroup {
controls: { form: FormControl, to: FormControl }
}
]
...
},
travellers: FormArray {
...
controls: [
0: FormGroup {
controls: { name: FormControl }
}
]
...
}
}
...
}
That seems to be good.
But I don't know why I can't access to the controls with form.controls.travel.controls or form.controls['travel'].controlsI always get the error : Property 'controls' does not exist on type 'AbstractControl'
In HTML :
<form class="dynamic-form" [formGroup]="form" (ngSubmit)="submitted.emit(form.value)">
<ng-container *ngFor="let array of objectKeys(config)">
<div [formArrayName]="array">
<ng-container *ngFor="let field of config[array]; let i = index" [formGroupName]="i">
<ng-container dynamicField [config]="field" [group]="form.controls[array].controls[i]"></ng-container>
</ng-container>
</div>
</ng-container>
</form>
But that doesn't work...
{{ form.value }} return the correct object :
{
"travel": [
{
"from": null,
"to": null
},
{
"from": null,
"to": null
}
],
"travellers": [
{
"name": null
}
]
}
Do you how to make it works ?
UPDATE
Maybe that the mistake is here :
import { Directive, Input, ComponentFactoryResolver, OnInit, ViewContainerRef } from '#angular/core';
import { FormGroup } from '#angular/forms';
import { FormButtonComponent, FormInputComponent, FormSelectComponent, FormResetComponent, FormDateComponent, FormNumberComponent } from '../components';
const components = {
button: FormButtonComponent,
input: FormInputComponent
};
#Directive({
selector: '[dynamicField]'
})
export class DynamicFieldDirective implements OnInit {
#Input()
config;
#Input()
group: FormGroup;
component;
constructor (
private resolver: ComponentFactoryResolver,
private container: ViewContainerRef
) {}
ngOnInit () {
const component = components[this.config.type];
const factory = this.resolver.resolveComponentFactory<any>(component);
this.component = this.container.createComponent(factory);
this.component.instance.config = this.config;
this.component.instance.group = this.group;
}
}
UPDATE 2
BuilderFormComponent.html:12 ERROR Error: No component factory found for undefined. Did you add it to #NgModule.entryComponents?
at noComponentFactoryError (core.es5.js:3202)
at CodegenComponentFactoryResolver.webpackJsonp.../../../core/#angular/core.es5.js.CodegenComponentFactoryResolver.resolveComponentFactory (core.es5.js:3267)
at BuilderFieldDirective.webpackJsonp.../../../../../src/app/builder-form/directives/builder-field.directive.ts.BuilderFieldDirective.ngOnInit (builder-field.directive.ts:35)
at checkAndUpdateDirectiveInline (core.es5.js:10856)
at checkAndUpdateNodeInline (core.es5.js:12357)
at checkAndUpdateNode (core.es5.js:12296)
at debugCheckAndUpdateNode (core.es5.js:13160)
at debugCheckDirectivesFn (core.es5.js:13101)
at Object.eval [as updateDirectives] (BuilderFormComponent.html:13)
at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13086)
View_BuilderFormComponent_2 # BuilderFormComponent.html:12
webpackJsonp.../../../core/#angular/core.es5.js.DebugContext_.logError # core.es5.js:13426
webpackJsonp.../../../core/#angular/core.es5.js.ErrorHandler.handleError # core.es5.js:1080
(anonymous) # core.es5.js:4819
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke # zone.js:392
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run # zone.js:142
webpackJsonp.../../../core/#angular/core.es5.js.NgZone.runOutsideAngular # core.es5.js:3844
webpackJsonp.../../../core/#angular/core.es5.js.ApplicationRef_.tick # core.es5.js:4819
webpackJsonp.../../../core/#angular/core.es5.js.ApplicationRef_._loadComponent # core.es5.js:4787
webpackJsonp.../../../core/#angular/core.es5.js.ApplicationRef_.bootstrap # core.es5.js:4775
(anonymous) # core.es5.js:4546
webpackJsonp.../../../core/#angular/core.es5.js.PlatformRef_._moduleDoBootstrap # core.es5.js:4546
(anonymous) # core.es5.js:4508
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke # zone.js:392
onInvoke # core.es5.js:3890
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke # zone.js:391
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run # zone.js:142
(anonymous) # zone.js:844
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask # zone.js:425
onInvokeTask # core.es5.js:3881
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask # zone.js:424
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask # zone.js:192
drainMicroTaskQueue # zone.js:602
Promise resolved (async)
scheduleMicroTask # zone.js:585
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask # zone.js:414
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleTask # zone.js:236
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleMicroTask # zone.js:256
scheduleResolveOrReject # zone.js:842
ZoneAwarePromise.then # zone.js:932
webpackJsonp.../../../core/#angular/core.es5.js.PlatformRef_._bootstrapModuleWithZone # core.es5.js:4537
webpackJsonp.../../../core/#angular/core.es5.js.PlatformRef_.bootstrapModule # core.es5.js:4522
../../../../../src/main.ts # main.ts:11
__webpack_require__ # bootstrap 92732b2f740421148d04:54
0 # main.bundle.js:1187
__webpack_require__ # bootstrap 92732b2f740421148d04:54
webpackJsonpCallback # bootstrap 92732b2f740421148d04:25
(anonymous) # main.bundle.js:1
BuilderFormComponent.html:12 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 1, nodeDef: {…}, elDef: {…}, elView: {…}}
#yurzui Ok my bad, I've needed to loop on config in directive ... OMG I lost so much time with it !! Thank you for your help, it helped me to understand the mistake.

Angular2 dynamic form with remote metadata

I created a dynamic form following the instructions in the angular cookbook and then I've tried to create the form with metadata that I have in my database.
I made an HTTP request to the get field types, names, ids, etc. but when I try to build the form as in the angular example, nothing happens or I get errors on console.
Here's the code from the tutorial:
export class AppComponent {
questions: any[];
constructor(service: QuestionService) {
this.questions = service.getQuestions();
}
}
And this is what I did:
export class AppComponent implements OnInit {
campos: any[] = [];
constructor(private servico: FormDadosService) {}
ngOnInit() {
this.servico.getCampos().subscribe(this.processaCampos);
}
processaCampos(dados) {
for (let i = 0; i < dados.length; i++) {
this.campos.push(new CampoBase({
nome: dados[i].ZI2_NOME,
label: dados[i].ZI2_DESC,
ordem: dados[i].ZI2_ORDEM,
obrigatorio: dados[i].ZI2_OBRIGAT,
tamanho: dados[i].ZI2_TAM,
valor: '',
tipoCampo: dados[i].ZI2_TIPO
}))
}
}
}
I am getting this error:
error_handler.js:50EXCEPTION: Cannot read property 'push' of undefined
I think I need to know a way to render the form after all data about it has arrived from my HTTP request.
I made it work this way:
export class AppComponent implements OnInit {
campos: any[] = [];
constructor(private servico: FormDadosService) { }
ngOnInit() {
this.servico.getCampos().subscribe((data) => {
data.forEach(campo => {
this.campos.push(new CampoBase({
valor: '',
nome: campo.ZI2_CAMPO,
label: campo.ZI2_DESC,
tipoCampo: campo.ZI2_TIPO,
tamanho: campo.ZI2_TAM
}))
});
});
}
}
This question can be marked as solved.
Thanks everyone.

angular2-mdl table component with server side data

I experiment with Angular 2 - Material Design Lite especially with the table component but I can not figure out how would I pass data from server on ajax request. Here is the example provided for table initialisation.
How would I pass data from restAPI to table component?
Here I have a kind of working example. I placed the initial data on my Component Init method where I call the DataService which populates the table. I'm not sure if is the right workaround but at this point I have data in table.
import { Component, ViewChild, ViewContainerRef, OnInit, Pipe, PipeTransform } from '#angular/core';
import { MdDialog, MdDialogConfig, MdIcon } from "#angular/material";
import { AuthenticationService, DialogsService, DataService } from '../../../services/';
import { RouterModule, Routes, Router } from '#angular/router';
import {
IMdlTableModelItem,
MdlDefaultTableModel
} from 'angular2-mdl';
export interface ITableItem extends IMdlTableModelItem {
username: string;
email: string;
role: string;
unitPrice: number;
}
#Component({
selector: 'employees',
templateUrl: 'app/layouts/secure/employees/employees.html',
providers: [DialogsService, MdIcon]
})
export class EmployeesComponent implements OnInit {
public message: string;
public employees: any[];
public result: any;
public showSearchBar: false;
public tableData:[ITableItem];
public selected;
public tableModel = new MdlDefaultTableModel([
{key:'username', name:'Username', sortable:true},
{key:'email', name:'Email', sortable:true},
{key:'role', name:'Role', sortable:true},
{key:'status', name:'Status', sortable:true},
{key:'unitPrice', name:'Test', numeric:true}
]);
constructor(
private dialogsService: DialogsService,
public viewContainerRef: ViewContainerRef,
private _dataService : DataService,
private router: Router
) {
}
openDialog() {
this.dialogsService
.confirm('User Form', 'Are you sure you want to do this?', this.viewContainerRef)
.subscribe(res => this.result = res);
}
toggleSearch() {
console.log(this)
}
ngOnInit() {
var self = this;
this._dataService
.GetAll('employees')
.subscribe( data => {
data = Object.keys(data).map((key)=>{ return data[key]})
this.employees = data;
this.tableData = data;
this.tableModel.addAll(this.tableData);
}, error => console.log(error),
() => function ( data ) {
this.tableData = this.employees;
this.tableModel.addAll(this.tableData);
this.selected = this.tableData.filter( data => data.selected);
},
);
}
generateArray(obj){
return Object.keys(obj).map((key)=>{ return obj[key]});
}
selectionChanged($event){
this.selected = $event.value;
}
}
#fefe made it a little more difficult than it had to be, at least with the current version. The magic of the as keyword can do the heavy lifting.
For example my class setup looks like:
import...
export interface IUnreadMessage extends IMdlTableModelItem {
messageId: number;
subject: string;
from: string;
}
#Component ...
export class ...
private unreadMessagesTable = new MdlDefaultTableModel([
{key: 'messageId', name: 'Message ID'},
{key: 'subject', name: 'Subject'},
{key: 'from', name: 'From'}
]);
Then in my ajax call I have:
...ajax call here).subscribe(value => {
const messages = value as Array<IUnreadMessage>;
this.unreadMessagesTable.addAll(messages);
},
error => {
...error handler here...
});
Make sure your interface is EXACTLY (including case) the same as your returned ajax data and it should hook right up!

How to perform async validation using reactive/model-driven forms in Angular 2

I have an email input and I want to create a validator to check, through an API, if the entered email it's already in the database.
So, I have:
A validator directive
import { Directive, forwardRef } from '#angular/core';
import { Http } from '#angular/http';
import { NG_ASYNC_VALIDATORS, FormControl } from '#angular/forms';
export function validateExistentEmailFactory(http: Http) {
return (c: FormControl) => {
return new Promise((resolve, reject) => {
let observable: any = http.get('/api/check?email=' + c.value).map((response) => {
return response.json().account_exists;
});
observable.subscribe(exist => {
if (exist) {
resolve({ existentEmail: true });
} else {
resolve(null);
}
});
});
};
}
#Directive({
selector: '[validateExistentEmail][ngModel],[validateExistentEmail][formControl]',
providers: [
Http,
{ provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() => ExistentEmailValidator), multi: true },
],
})
export class ExistentEmailValidator {
private validator: Function;
constructor(
private http: Http
) {
this.validator = validateExistentEmailFactory(http);
}
public validate(c: FormControl) {
return this.validator(c);
}
}
A component
import { Component } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
import { ExistentEmailValidator } from '../../directives/existent-email-validator';
#Component({
selector: 'user-account',
template: require<string>('./user-account.component.html'),
})
export class UserAccountComponent {
private registrationForm: FormGroup;
private registrationFormBuilder: FormBuilder;
private existentEmailValidator: ExistentEmailValidator;
constructor(
registrationFormBuilder: FormBuilder,
existentEmailValidator: ExistentEmailValidator
) {
this.registrationFormBuilder = registrationFormBuilder;
this.existentEmailValidator = existentEmailValidator;
this.initRegistrationForm();
}
private initRegistrationForm() {
this.registrationForm = this.registrationFormBuilder.group({
email: ['', [this.existentEmailValidator]],
});
}
}
And a template
<form novalidate [formGroup]="registrationForm">
<input type="text" [formControl]="registrationForm.controls.email" name="registration_email" />
</form>
A've made other validator this way (without the async part) and works well. I think te problem it's related with the promise. I'm pretty sure the code inside observable.subscribe it's running fine.
What am I missing?
I'm using angular v2.1
Pretty sure your problem is this line:
...
email: ['', [this.existentEmailValidator]],
...
You're passing your async validator to the synchronous validators array, I think the way it should be is this:
...
email: ['', [], [this.existentEmailValidator]],
...
It would probably be more obvious if you'd use the new FormGroup(...) syntax instead of FormBuilder.