Mostrando entradas con la etiqueta Angular. Mostrar todas las entradas
Mostrando entradas con la etiqueta Angular. Mostrar todas las entradas

Tablas con filtros en Angular - swimlane/ngx-datatable'

http://swimlane.github.io/ngx-datatable/


Instalación
npm i @swimlane/ngx-datatable --save --legacy-peer-deps

Agregar en tsconfig.json (dentro de compilerOptions)
"strictPropertyInitialization": false

Esto es para evitar un error de tipos que da, busqué en google y parece que lo resuelven así, no me gusta demasiado, pero por ahora déjalo de este modo.

En app.module.ts
import { NgxDatatableModule } from '@swimlane/ngx-datatable'; 

imports: [
    ...
    ...
    NgxDatatableModule
  ] 

En el .html
<input
        type="text"
        style="padding: 8px; margin: 15px auto; width: 30%;"
        placeholder="Filtrar..."
        (keyup)="updateFilter($event)"
      />
<div>
  <ngx-datatable #table [rows]="rows" [columns]="columns"> </ngx-datatable>
</div>

En el .ts
import { Component, ViewChild } from '@angular/core';
import { DatatableComponent } from '@swimlane/ngx-datatable'; 

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

export class AppComponent {
  @ViewChild(DatatableComponent) table: DatatableComponent; 

  rows = [
    { name: 'Austin', gender: 'Male', company: 'Swimlane' },
    { name: 'Dany', gender: 'Male', company: 'KFC' },
    { name: 'Molly', gender: 'Female', company: 'Burger King' }
  ]; 

  temp = this.rows; 

  columns = [{ prop: 'name' }, { name: 'Gender' }, { name: 'Company' }]; 
  updateFilter(event: any) {

  const val = event.target.value.toLowerCase();
 

  const temp = this.temp.filter(function (d) {
      return d.name.toLowerCase().indexOf(val) !== -1 || !val ||
                d.gender.toLowerCase().indexOf(val) !== -1 ||
                d.company.toLowerCase().indexOf(val) !== -1;
    });   

    this.rows = temp;   
    this.table.offset = 0;   //ir a 1er página luego de hacer cualquier cambio
  
}

Si no se despliega imagen de assets

 Agregar src/assets en angular.json


"assets": [
              {
                "glob": "_redirects",
                "input": "src",
                "output": "/"
              },
              {
                "glob": "**/*.svg",
                "input": "node_modules/ionicons/dist/ionicons/svg",
                "output": "./svg"
              },
              "src/manifest.webmanifest",
              "src/manifest.webmanifest",
              "src/assets"
            ],

Could not reach Cloud Firestore backend. Connection failed 1 times. Most recent error: FirebaseError: [code=unknown]: Fetching auth token failed: getToken aborted

 Esto ocurre cuando se guarda el proyecto en Visual Code (lo cual vuelve a recargar todo) y despues se intenta hacer el login.

Es como si quisiera usar el token viejo para autenticarse.

La solucion, borrar los datos de navegacion (Ctrl+Shift+Supr)

Y luego darle Ctrl-P a la página.

Can't bind to 'formGroup' since it isn't a known property of 'form'

 -en declarations, agregar los componentes (ej, EdicionVehiculosComponent)

-en imports agregar:

CommonModule,
FormsModule,
ReactiveFormsModule


@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    EdicionVehiculosComponent,
    ListadoVehiculosComponent
  ],

  imports: [

    BrowserModule,
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    AppRoutingModule,
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFirestoreModule,
    AngularFireStorageModule
  ],

  providers: [],
  bootstrap: [AppComponent]
})

Scroll no funciona en android con Hammer y evento (press)


<ion-content>
  <ion-list>
    <ion-item *ngFor="let reclamo of listaReclamos" (click)="historialReclamo(reclamo)" (press)="prueba(reclamo.id, reclamo.texto)">
      <ion-label text-wrap>{{reclamo.texto}}</ion-label>

      <ion-note slot="end">{{reclamo.fecha.toMillis() | date:'dd/MM/yyyy HH:mm'}} <br> 
                           {{reclamo.nickUsuario}} <br>
                           
        <ion-badge *ngIf="reclamo.estado == 'resuelto'" color="success">resuelto</ion-badge>
        <ion-badge *ngIf="reclamo.estado == 'atrasado'" color="danger">atrasado</ion-badge>
        <ion-badge *ngIf="reclamo.estado == 'pendiente'" color="warning">pendiente</ion-badge>
      </ion-note>
    </ion-item>
  </ion-list>

  <ion-fab vertical="bottom" horizontal="end" slot="fixed">
    <ion-fab-button (click)="nuevoReclamo()">
      <ion-icon name="add"></ion-icon>
    </ion-fab-button>
  </ion-fab>
</ion-content>

 al utilizar (press), deja de andar el scroll en la lista

para solucionarlo,

en app.module.ts, poner en false pinch y rotate:

export class CustomHammerConfig extends HammerGestureConfig {
  overrides = {
      'press': { time: 1000 },  //set press delay for 1 second
      'pinch': { enable: false },
      'rotate': { enable: false }
  }
}


Can't bind to 'ngIf' since it isn't a known property of 'div'

 Si al crear un componente da este error,

hay que agregar el componente en app.module.ts, en el array declarations: ej, si el componente se llama PopoverEdicionReclamoComponent:

@NgModule({
  declarations: [AppComponentPopoverEdicionReclamoComponent],



Angular en IE - Habilitar custom headers y cors en WebApi (SEC7123)

Proyecto de ejemplo que tiene este cambio: Creditos


A partir de Angular 8 no es necesario modificar el archivo polyfills.


1. Agregar en WebApiConfig.cs

            var cors = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(cors);

2. Agregar en web.config (dentro de 

  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <!-- <add name="Access-Control-Allow-Origin" value="*" />  -->
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
      </customHeaders>
    </httpProtocol>
 
  </system.webServer>

Angular FlexLayout

https://alligator.io/angular/flex-layout/


https://alligator.io/angular/flex-layout/


Instalación:

npm install @angular/flex-layout --save

import { FlexLayoutModule } from "@angular/flex-layout";

agregar en imports:

FlexLayoutModule


Ejemplo:

<mat-card>
    <div class="container" fxLayout="row" fxLayout.xs="column" fxLayoutWrap fxLayoutGap="0%" fxLayoutAlign="center">
        <div fxFlex="60%" style="background-color: gray;">
           
            <form (ngSubmit)="login()">
                <div>   
                    <mat-form-field>
                        <input matInput placeholder="Usuario" [(ngModel)]='usuario' name='usuario'>
                    </mat-form-field>         
                </div>

                <div>   
                    <mat-form-field>
                        <input matInput placeholder="Password" [(ngModel)]='password' name='password' type="password">
                    </mat-form-field>         
                </div>

                <button mat-raised-button color="primary" type="submit">Enviar</button>
            </form>                   
        </div>

        <div fxFlex="40%" style="background-color: lightyellow;">
            Ingrese sus datos
        </div>
    </div>
</mat-card>

Creacion de nuevo sitio Angular Material


https://www.smashingmagazine.com/2018/10/news-application-with-angular-and-material-design/


ng new proyecto1
cd proyecto1

npm install --save @angular/material @angular/animations @angular/cdk

ng serve


en app.module.ts, agregar todos los modulos que figuran en este link:

https://expressraider.blogspot.com/2019/02/importacion-de-todos-los-modulos-de.html?m=0


Importacion de todos los modulos de Material

Para instalar angular material:

npm install --save @angular/material @angular/cdk
ng add @angular/material


Para no tener que importar todos los modulos material en cada pagina que se utilicen, se puede crear un modulo que tenga todas las definiciones y luego importar solamente ese:

1. Crear un archivo llamado material.module.ts y agregarle esto:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatButtonModule} from '@angular/material/button';
import {MatInputModule} from '@angular/material/input';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import {MatDatepickerModule} from '@angular/material/datepicker';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatNativeDateModule, MAT_DATE_LOCALE} from '@angular/material/core';
import {MatRadioModule} from '@angular/material/radio';
import {MatSelectModule} from '@angular/material/select';
import {MatSliderModule} from '@angular/material/slider';
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {MatMenuModule} from '@angular/material/menu';
import {MatSidenavModule} from '@angular/material/sidenav';
import {MatToolbarModule} from '@angular/material/toolbar';
import {MatListModule} from '@angular/material/list';
import {MatGridListModule} from '@angular/material/grid-list';
import {MatCardModule} from '@angular/material/card';
import {MatStepperModule} from '@angular/material/stepper';
import {MatTabsModule} from '@angular/material/tabs';
import {MatExpansionModule} from '@angular/material/expansion';
import {MatButtonToggleModule} from '@angular/material/button-toggle';
import {MatChipsModule} from '@angular/material/chips';
import {MatIconModule} from '@angular/material/icon';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import {MatProgressBarModule} from '@angular/material/progress-bar';
import {MatDialogModule} from '@angular/material/dialog';
import {MatTooltipModule} from '@angular/material/tooltip';
import {MatSnackBarModule} from '@angular/material/snack-bar';
import {MatTableModule} from '@angular/material/table';
import {MatSortModule} from '@angular/material/sort';
import {MatPaginatorModule} from '@angular/material/paginator';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    MatCheckboxModule,
    MatCheckboxModule,
    MatButtonModule,
    MatInputModule,
    MatAutocompleteModule,
    MatDatepickerModule,
    MatNativeDateModule,
    MatFormFieldModule,
    MatRadioModule,
    MatSelectModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatMenuModule,
    MatSidenavModule,
    MatToolbarModule,
    MatListModule,
    MatGridListModule,
    MatCardModule,
    MatStepperModule,
    MatTabsModule,
    MatExpansionModule,
    MatButtonToggleModule,
    MatChipsModule,
    MatIconModule,
    MatProgressSpinnerModule,
    MatProgressBarModule,
    MatDialogModule,
    MatTooltipModule,
    MatSnackBarModule,
    MatTableModule,
    MatSortModule,
    MatPaginatorModule

  ],
  exports: [
    MatCheckboxModule,
    MatCheckboxModule,
    MatButtonModule,
    MatInputModule,
    MatAutocompleteModule,
    MatDatepickerModule,
    MatNativeDateModule,
    MatFormFieldModule,
    MatRadioModule,
    MatSelectModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatMenuModule,
    MatSidenavModule,
    MatToolbarModule,
    MatListModule,
    MatGridListModule,
    MatCardModule,
    MatStepperModule,
    MatTabsModule,
    MatExpansionModule,
    MatButtonToggleModule,
    MatChipsModule,
    MatIconModule,
    MatProgressSpinnerModule,
    MatProgressBarModule,
    MatDialogModule,
    MatTooltipModule,
    MatSnackBarModule,
    MatTableModule,
    MatSortModule,
    MatPaginatorModule
  ],
  providers: [
    {provide: MAT_DATE_LOCALE, useValue: 'es-ES'},
  ],
})

export class MaterialModule { }
2. Para la pagina en la que se quiere utilizar material, en el archivo module (ej, home.module.ts) agregar:

import { MaterialModule } from '../_material/material.module';

y en imports:

MaterialModule

3. En home.page.html, agregar algo para testearlo:

<ion-content padding>
    <div style="text-align: center;">
        <mat-button-toggle-group name="fontStyle" aria-label="Font Style" class="example-full-width">
          <mat-button-toggle color="primary" value="opcion1">Opcion1</mat-button-toggle>
          <mat-button-toggle color="primary" value="opcion2">Opcion2</mat-button-toggle>    
        </mat-button-toggle-group>        
    </div>
    
    <div style="text-align: center;">
      <mat-form-field class="example-full-width">
        <input matInput placeholder="Nombre y apellido">
      </mat-form-field>  
    </div>
  
    <div style="text-align: center;">
      <mat-form-field class="example-full-width">
        <input matInput placeholder="Email">
      </mat-form-field>  
    </div>    
</ion-content>

Subir archivos con Angular y WebApi



app.component.html

<form [formGroup]="form" (ngSubmit)="onSubmit()" class="form-horizontal form-control-sm">
  <div class="form-row">
    <label for="nombre" class="col-sm-1 control-label form-control-sm text-right">Nombre</label>
    <div class="col-sm-1">
      <input class="form-control form-control-sm" formControlName="nombre">
    </div>
  </div>

  <div class="form-row mb-2">
    <label for="foto" class="col-sm-1 control-label form-control-sm text-right">Foto</label>
    <div class="col-sm-3">
      <img src="./assets/noimage.png" id="previewFoto" name="previewFoto" style="width: 150px; height: 150px;cursor: pointer" onClick="document.getElementById('foto').click();"
      />
    </div>
    <input class="form-control form-control-sm" id="foto" type="file" accept=".xlsx" (change)="upload($event)"
      #fileInput style="display: none">
  </div>

  <input type="submit" value="Guardar" [disabled]="!form.valid" class="btn btn-primary col-sm-1">
</form>


app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from "@angular/forms";
import { DatosService } from './_servicios/datos.service';
import { Datos } from './_modelos/datos';
import { CustomResponse } from './_modelos/custom-response';
import { ResponseMessageCode } from './_servicios/enumerados';
//import { Archivo } from './_modelos/archivo';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  datos = new Datos();
  form: FormGroup;

  constructor(private fb: FormBuilder, private data : DatosService) {
    this.createForm();
  }

  createForm() {
    this.form = this.fb.group({     
  nombre: [''],
      foto: ['']
    });
  }

  upload(event) {
    this.onFileChange(event);
  }

  onFileChange(event) {
    if (event.target.files.length > 0) {
      let archivoSeleccionado = event.target.files[0];

      let reader = new FileReader();
      reader.readAsDataURL(archivoSeleccionado);
      let _this = this;

      reader.onloadend = function () {
        _this.form.patchValue({
          foto: (<string>reader.result).split('base64,')[1]
        });
      }
    }
  }

  onSubmit() {       
    this.datos.nombre = this.form.get('nombre').value;

    if (this.datos.contenido != 'undefined') {
      this.datos.contenido = this.form.get('foto').value;
    }

    this.data.guardar(this.datos).subscribe(
      (response: CustomResponse<any>) => {
        if (response.messageCode == ResponseMessageCode.OK) {
          console.log("todo ok");
        } else {
          console.log("mal");     
        }
      }
    );
  }

  ngOnInit() {
  }
}


app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: 'home', component: AppComponent }
]

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    RouterModule.forRoot(routes)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }



datos.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class DatosService {
  constructor(public http: HttpClient) { }

  public guardar(datos): Observable<any> {
    return this.http.post<any>("http://localhost/servicios/api/creditos/subirarchivo", datos);
  }
}

custom-response.ts

export class CustomResponse<T> {
   messageCode: number;
   message: string;
   data: T;
}

datos.ts

export class Datos {
    nombre: string;
    contenido: string;
}


WebApi C#

[AllowAnonymous]
[OverrideAuthentication]
[HttpPost]
public IHttpActionResult SubirArchivo(Arch datos)
{
var path = System.Web.HttpContext.Current.Server.MapPath("~") + @"\xls\archivo.xlsx";
if (File.Exists(path))
File.Delete(path);

File.WriteAllBytes(path, datos.Contenido);

var mensaje = new { error = false, mensaje = "" };

return this.Ok(mensaje);
}

public class Arch
{
    [JsonProperty("nombre")]
    public string Nombre { get; set; }
    [JsonProperty("contenido")]
    public byte[] Contenido { get; set; }
}

Bajar archivo desde WebApi con Angular 6


WebApi:

[HttpGet]
public HttpResponseMessage GenExcel()
{
var rutaExcelTemp = @"C:\path_del_sitio_web\Xls\TasaMedia.xlsx";

var nombreArchivoGenerado = "TasaMedia_" + DateTime.Now.Day + "_" + DateTime.Now.Month + "_" + DateTime.Now.Year + "_" + DateTime.Now.Hour + DateTime.Now.Minute + DateTime.Now.Second + DateTime.Now.Millisecond + ".xlsx";//nombre del nuevo archivo

var reportStream = new StreamContent(File.Open(rutaExcelTemp, FileMode.Open, FileAccess.Read));

var result = Request.CreateResponse(HttpStatusCode.OK);

result.Content = reportStream;

result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/force-download");
result.Content.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = Path.GetFileName(nombreArchivoGenerado)
};
return result;     
}



Angular:

  import { Observable } from 'rxjs';
  import { HttpClient } from "@angular/common/http";

  downloadFile(url: string) {
    return this.http.get('http://localhost' + url', {
      responseType: 'blob', observe: 'response'
    }).subscribe(res => {
      let contentDisposition = res.headers.get('Content-Disposition');
      var result = contentDisposition.split(';')[1].trim().split('=')[1];
      let archivo = result.replace(/"/g, '');

      console.log('start download:', res);
      var url = window.URL.createObjectURL(res.body);
      var a = document.createElement('a');
      document.body.appendChild(a);
      a.setAttribute('style', 'display: none');
      a.href = url;
      a.download = archivo; //res.filename;
      a.click();
      window.URL.revokeObjectURL(url);
      a.remove(); // remove the element
    }, error => {
      console.log('download error:', JSON.stringify(error));
    }, () => {
      console.log('Completed file download.')
    });
  }

Actualizacion a Angular 6 desde 5.2

1. npm install -g @angular/cli
2. npm i -g npm
3. npm install @angular/cli
4. ng update @angular/cli
5. npm install --save-dev @angular/cli@latest
6. ng update @angular/cli
7. ng update @angular/core
8. ng update @angular/material
9. ng update
10. npm install -g rxjs-tslint
11. rxjs-5-to-6-migrate -p src/tsconfig.app.json
12. npm uninstall rxjs-compat
13. cerrar y abrir visual code


https://blog.ng-classroom.com/blog/angular/Angular-upgrade/?utm_source=browser&utm_medium=push_notification&utm_campaign=PushCrew_notification_1525897317&pushcrew_powered=1


Leer una imagen de mysql y mostrarla en Angular

en este ejemplo, foto es el campo leido de mysql, tiene un atributo data que es la imagen codificada.

var preview = document.querySelector('img');                           
var arrayBufferView = new Uint8Array(foto.data);
var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
var urlCreator = window.URL;
var imageUrl = urlCreator.createObjectURL(blob);       
preview.src = imageUrl;



Validaciones custom con Angular 5


app.component.html

<form [formGroup]="agendaForm" (ngSubmit)="submit()">
  <input formControlName="usuario">
  <input formControlName="telefono">

  <div *ngIf="agendaForm.get('usuario').errors">
     <div *ngIf="agendaForm.get('usuario').errors['required']">
          Nombre de usuario es requerido
     </div>
  </div>

  <div *ngIf="!agendaForm.valid">
       Hay errores en el form!!!
  </div>

  <button type="submit" [disabled]="!agendaForm.valid">Enviar</button>
</form>

app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormControl, ValidatorFn, AbstractControl } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  agendaForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.crearForm();
  }

  crearForm() {
    this.agendaForm = this.fb.group({
      usuario: ['texto precargado', Validators.required],
      telefono: ['', Validators.compose(
                        [Validators.required,
                         this.telefonoValidator(/^[679]{1}[0-9]{8}$/)
                        ]
                      )
                ]             
    });
  }

  telefonoValidator(telefonoExp: RegExp): ValidatorFn {
    return (control: AbstractControl): {[key: string]: any} => {
      const telefono = telefonoExp.test(control.value);
      return !telefono ? {'telefonoNumber': {value: control.value}} : null;
    };
  }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent    
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Crear formulario con FormBuilder ReactiveForms en Angular 5

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent   
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormControl, ValidatorFn, AbstractControl } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  loginForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.crearForm();
  }

  crearForm() {
    this.loginForm = this.fb.group({
      usuario: ['texto precargado', Validators.required],
      password: ['']               
    });
  }
}

app.component.html

<form [formGroup]="loginForm" (ngSubmit)="submit()">
  <input formControlName="usuario">
  <input formControlName="password">

  <button type="submit" [disabled]="!loginForm.valid">Enviar</button>
</form>

Subir archivos junto a otros campos en Angular y NodeJS [** 100% OK **]

setup inicial:

npm install --save express body-parser multer fs path

frontend:

app.component.html

<img src="" name="img" />

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <div>
    <label for="nombre">Name</label>
    <input type="text" id="nombre" placeholder="Ingrese el nombre" formControlName="nombre">
  </div>
  <div>
    <label for="foto">Foto</label>
    <input type="file" id="foto" (change)="onFileChange($event)" #fileInput>
    <button type="button" (click)="clearFile()">clear file</button>
  </div>
  <button type="submit" [disabled]="form.invalid || loading">Submit</button>
</form>

app.component.ts

import { Component, ElementRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from "@angular/common/http";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  form: FormGroup;
  loading: boolean = false;

  @ViewChild('fileInput') fileInput: ElementRef;

  constructor(private fb: FormBuilder, private http: HttpClient) {
    this.createForm();
  }

  createForm() {
    this.form = this.fb.group({
      nombre: ['', Validators.required],
      foto: null
    });
  }

  onFileChange(event) {
    if(event.target.files.length > 0) {
      let file = event.target.files[0];
      this.form.get('foto').setValue(file);
     
      var preview = document.querySelector('img');     
      var reader  = new FileReader();
   
      reader.onloadend = function () {
        preview.src = reader.result;
      }
   
      if (file) {
        reader.readAsDataURL(file);
      } else {
        preview.src = "";
      }

    }
  }

  onSubmit() {
    let formModel = new FormData();
    formModel.append('nombre', this.form.get('nombre').value);
    formModel.append('foto', this.form.get('foto').value);
   
    this.loading = true;

    this.http.post("http://localhost:8080/upload", formModel).subscribe((datos) => {               
      console.log(datos);   
   });     
  }

  clearFile() {
    this.form.get('foto').setValue(null);
    this.fileInput.nativeElement.value = '';
  }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule, Http } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { HttpClient } from "@angular/common/http";

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


servidor:

var express = require("express")
    app = express(),
    bodyParser = require("body-parser"),
    multer  = require('multer'),
    fs = require('fs'),
    path = require('path');

var upload  = multer({ storage: multer.memoryStorage() });

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

var router = express.Router();

app.use(function (req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization');
    res.setHeader('Access-Control-Allow-Credentials', true);             

    next();
});

app.use(router);

router.post('/upload', upload.array('foto'), function(req, res) {
    console.log("archivos son........: " + req.files);
    console.log(req.files[0]);
   
    console.log("el nombre es: " + req.body.nombre);

    var buffer = req.files[0].buffer;
    var magic = buffer.toString('hex', 0, 4);
    var filename = req.files[0].fieldname + '-' + Date.now() + path.extname(req.files[0].originalname);

    fs.writeFile('/temp/' + filename, buffer, 'binary', function (err) {
        if (err) throw err
            res.end('File is uploaded')
    })

    res.send(JSON.stringify({resultado : 'ok'}));       
});

app.listen(8080, function() {
    console.log("Node server running on http://localhost:8080");
});