7

first of all I am a complete beginner at this kind of programming with nodejs, angular2 and typescript. Basically i start reading on https://angular.io/docs/ts/latest/guide/forms.html and https://angular.io/docs/ts/latest/guide/router.html#!#base-href to extend my application with new pages. I use mdl to use material components on my application.
angular 2 seems to handly reloading and routing different so i get following issue:
routing
reloading
I try to unterstand whats happening, can someone explain me what the difference between reloading and routing in angular2 and how I can fit the handling of routing to the behaviour of reloading?

Update #1:
index.html:

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Title</title>
  <script defer src="/assets/js/material.min.js"></script>
  <link rel="stylesheet" href="/assets/css/font-awesome.min.css">
  <link rel="stylesheet" href="/assets/css/material.min.css">
  <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root><md-spinner></md-spinner></app-root>
</body>
</html>

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './pages/layout/app.component';
import { HomeComponent } from './pages/home/app.component';
import { LoginComponent } from './pages/myaccount/login.component';
import { NotFoundComponent } from './pages/error/404.component';
import { RegisterComponent } from './pages/myaccount/register.component';
import { RouterModule, Routes } from '@angular/router';
import { LoginService } from './service/LoginService';

const appRoutes: Routes = [
  {
      path: '',
      component: HomeComponent
  },
  { path: 'series', component: AppComponent },
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
  { path: '**', component: NotFoundComponent }
];

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    HomeComponent,
    RegisterComponent,
    NotFoundComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule.forRoot(appRoutes)
    ],
  providers: [LoginService],
  bootstrap: [AppComponent]
})
export class AppModule { }

register.html:

<div class="mdl-grid iv-padding" >
    <div class="mdl-layout-spacer"></div>
    <div class="mdl-cell mdl-cell--4-col">
      <div style="text-align:center;">
        <form (ngSubmit)="onSubmit()">
        <div class="iv-card-wide mdl-card mdl-shadow--2dp">
          <div class="mdl-card__title">
            <h2 class="mdl-card__title-text">Registrierung</h2>
          </div>
          <div class="mdl-card__supporting-text">
              <div class="text-field mdl-textfield mdl-js-textfield">
                <input class="mdl-textfield__input" required [(ngModel)]="model.username" name="username" type="text" id="username">
                <label class="mdl-textfield__label" for="username" >Username</label>
              </div>
              <br />
              <div class="text-field mdl-textfield mdl-js-textfield">
                <input class="mdl-textfield__input" [(ngModel)]="model.password" name="password" type="password" id="password">
                <label class="mdl-textfield__label" for="password">Password</label>
              </div>
              <br />
              <div class="text-field mdl-textfield mdl-js-textfield">
                <input class="mdl-textfield__input" [(ngModel)]="model.email" name="email" type="email" id="email">
                <label class="mdl-textfield__label" for="email">E-Mail</label>
              </div>
          </div>
          <div class="mdl-card__actions mdl-card--border">
            <button type="submit" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent">Registrieren</button>
          </div>
        </div>
        </form>
      </div>
    </div>
    <div class="mdl-layout-spacer"></div>
</div>

RegisterComponent

import { Component } from '@angular/core';
import { User } from '../../objects/user';

@Component({
  selector: 'app-root',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})

export class RegisterComponent {
  model = new User(0, "", "", "");
  submitted = false;
  onSubmit() {
    console.log("PW" + this.model.password);
  }
}
Björn Ternes
  • 1,137
  • 4
  • 14
  • 33

3 Answers3

0

Without seeing your source code it's hard to see the issue.

The simplified difference between reloading your page and using the router is:

  • The router will render the route inside the tags. This allows you to load components within your page dynamically without any page reloading.
  • Reloading your page results in the entire page being reloaded, event with AoT compilation, this is much more expensive. There shouldn't really be a need to reload, all navigation should be handled in the router.

As for your issue, it just seems like you are loading that component multiple times. If you are talking about the text overlapping with the tooltip that could be a dependency issue with how you are importing the material design components. Post your code and I'll try to help you out.

meanstack
  • 161
  • 1
  • 1
  • 8
0

So, I'm assuming that you're problem is that the label is overlapped by the input before reloading. That has nothing to do with routing / reloading (or at least is not the source of the problem). Your material design lite JS file is not doing his job !

I recreated the problem here and solved it by adding the lib here.

This could be caused by many factors :

  • MDL is loading it's script after the component is rendered.
  • Your MDL.js is corrupted / not working.
  • The 3rd part lib you're using is not linked properly.

If you're using angular-cli you need to add the library to the global scope. To do so, add the path to your lib in your .angular-cli.json file :

...
"scripts": [
  "/assets/js/material.min.js",
  ...
]
...
YounesM
  • 2,279
  • 15
  • 28
  • thanks for the answer, I add my scripts and styles to angular-cli, now it works without referencing it in my index.html. But i get still the same error. I replaced by MDL with a fresh version. – Björn Ternes Mar 25 '17 at 10:00
  • Is there any error displayed on the dev tools console ? – YounesM Mar 25 '17 at 13:47
  • unfortunately not, just a information about angular2 because its running in development mode. – Björn Ternes Mar 26 '17 at 21:23
0

Material Design Lite requires some extra work when you render the components dynamically. More information can be found in their docs

TLDR; You need to call componentHandler.upgradeElement after the elements have been injected into the DOM. An approach I've used in the past is described in the example below.

EDIT If you want a declarative solution this approach here seem like a pretty good one, but I have not used it myself.

I created a service that wraps the Material Lite componentHandler

import { Injectable } from '@angular/core';

export interface ComponentHandler {
    upgradeDom();

}

declare var componentHandler: ComponentHandler;


@Injectable()
export class MaterialService {
    handler: ComponentHandler;
    constructor() {
        this.handler = componentHandler;
    }

    // render on next tick
    render() {
        setTimeout(() => { this.handler.upgradeDom(); }, 0);
    }

}

Then you call the service's render function after the component has injected the elements into the DOM.

This is a very contrived example but demonstrates "where" to call render

import { Component, OnInit } from '@angular/core';
import { DataService } from 'services/data.service';
import { MaterialService } from 'services/material.service';

@Component({
    selector: 'app-thing',
    templateUrl: `
       <ul>
            <li *ngFor="let item of data">
              {{data}}
            </li>
       </ul>
    `
})
export class ThingComponent implements OnInit {
    data: string[]
    constructor(
        private service: DataService,
        private material: MaterialService
    ) { }

    ngOnInit() {
        this.service.getData()
        .subscribe(data => {
            this.data = data;
            this.material.render();
        });
     }
}
Community
  • 1
  • 1
wickdninja
  • 949
  • 1
  • 10
  • 15