In this tutorial, I will explain how to upload images in Angular 2. In this demo, I am using Angular 2 as front-end and node.js (with express template) as back-end along with MySQL as database. I am using Angular-cli to create the project. I hope you guys have already created the project using Angular-cli. If not, you can find how to create one.
You can also find both back-end and front-end links here.
Note
To run both projects, you need to install dependency from the package.json. You can simple do that by navigating to the project directory and writing the command "npm install".
Then, to run the back-end project, write "npm start"
Setting up the table in MySQL
- script file
- for student_tbl[code language = "sql"]
- CREATE TABLE IF NOT EXISTS `student_tbl` (`rno`
- int(11) NOT NULL, `name`
- varchar(50) DEFAULT NULL, `mobile_no`
- varchar(15) DEFAULT NULL, `student_img`
- varchar(1000) NOT NULL, PRIMARY KEY(`rno`)) ENGINE = InnoDB DEFAULT CHARSET = latin1;
Back-end using node.js
First, I will start from creating the back-end using node.js. If you want to know the steps for how to create REST API using node.js, you can go here.
So first, I will create dbconnection.js file which will store the hostname, username, and database name.
- var mysql = require('mysql');
- var connection = mysql.createPool({
- host: 'localhost',
- user: 'root',
- password: '',
- database: 'demo'
- });
- module.exports = connection;
Now, in the next step, I will create the student_model inside Models directory. It contains all the methods for fetching, inserting, and deleting the student records from the database.
- var db = require('../dbconnection');
- var fs = require('fs');
- var Student = {
- getAllStudent: function(callback) {
- return db.query("select * from student_tbl", callback);
- },
- deleteStudent: function(Student, callback) {
- if (Student.student_img != '') {
- var path = './public' + Student.student_img;
- fs.unlink(path, function(err) {
- if (err) {
- console.log(err);
- }
- console.log('Deleted successfuly')
- });
- }
- return db.query("delete from student_tbl where rno=?", [Student.rno], callback);
- },
- addStudent: function(Student, callback) {
- var dt = new Date();
- var text = "";
- var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- for (var i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length));
- var base64d = Student.student_img.replace(/^data:image\/png;base64,/, "");
- var path = "./public/images/" + text + dt.getDate() + dt.getMonth() + dt.getMilliseconds() + ".png";
- var path1 = "/images/" + text + dt.getDate() + dt.getMonth() + dt.getMilliseconds() + ".png";
- fs.writeFile(path, base64d, 'base64', function(err) {
- if (err) {
- return console.log(err);
- }
- console.log("The file was saved!");
- });
- return db.query("Insert into student_tbl values(?,?,?,?)", [Student.rno, Student.name, Student.mobile_no, path1], callback);
- }
- };
- module.exports = Student;
First, I need to import dbconnection.js and file system references to student_model.js file. In the above code, the first method "getAllStudent" simply returns all the records from the student_tbl.
The next method, "deleteStudent" deletes the record from the table and also deletes the images that are previously uploaded by the user using file system.
And, the last method "addStudent" adds new record to database and also uploads the images into the folder. Here, I am passing byte[] from body and creating image from byte[].
Now, set the routes in app.js.
- var express = require('express');
- var path = require('path');
- var favicon = require('serve-favicon');
- var logger = require('morgan');
- var cookieParser = require('cookie-parser');
- var bodyParser = require('body-parser');
- var cors = require('cors');
- var index = require('./routes/index');
- var users = require('./routes/users');
- var Students = require('./routes/Students');
- var app = express();
-
- app.set('views', path.join(__dirname, 'views'));
- app.set('view engine', 'jade');
-
-
- app.use(cors());
- app.use(logger('dev'));
- app.use(bodyParser.json({
- limit: '50mb'
- }));
- app.use(bodyParser.urlencoded({
- limit: '50mb',
- extended: false
- }));
- app.use(cookieParser());
- app.use(express.static(path.join(__dirname, 'public')));
- app.use('/', index);
- app.use('/users', users);
- app.use('/Students', Students);
-
- app.use(function(req, res, next) {
- var err = new Error('Not Found');
- err.status = 404;
- next(err);
- });
-
- app.use(function(err, req, res, next) {
-
- res.locals.message = err.message;
- res.locals.error = req.app.get('env') === 'development' ? err : {};
-
- res.status(err.status || 500);
- res.render('error');
- });
- module.exports = app;
Now, one important thing in app.js is that I am defining the limit of data. By default, it is set to 1 MB. So, I have extended it to 50 MB.
All is set up for the back-end, now it’s turn to set up the front-end in Angular 2.
Front-end using Angular 2
I will start from creating data structure for student.
student.ts
- export class Student {
- public constructor(public rno: number, public name: string, public mobile_no: string, public student_img: string) {}
- }
I have created one class for students which contains 4 columns like rno, name, mobile_no, and student_img.
Now, I will create a component to add a new student.
addstudent.component.html
- <div class="container">
- <form (ngSubmit)="studentSubmit()" #addform="ngForm">
- <div class="form-group"> <label for="id">rollno</label> <input type="number" [(ngModel)]="model.rno" name="rno" class="form-control" id="rno" required #rno="ngModel"> </div>
- <div [hidden]="rno.valid || rno.pristine" class="alert alert-danger"> Roll No is required </div>
- <div class="form-group"> <label for="name">Name</label> <input type="text" [(ngModel)]="model.name" name="name" class="form-control" id="name" required #name="ngModel"> </div>
- <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Student Name is required </div>
- <div class="form-group"> <label for="name">Mobile Number</label> <input type="text" [(ngModel)]="model.mobile_no" name="mobile_no" class="form-control" id="mobile_no" required #mobile_no="ngModel"> </div>
- <div [hidden]="mobile_no.valid || mobile_no.pristine" class="alert alert-danger"> Student Mobile Number is required </div>
- <div class="form-group"> <input type="file" name="student_img" required (change)="fileChange(input)" #input /> </div>
- <div> <img [attr.src]='file_srcs[0]' alt="" /> </div> <button type="submit" class="btn btn-default form-control" [disabled]="!addform.form.valid">Add Task</button> </form>
- </div>
Here, in the above HTML, I used <input type=”file” />, and created filechange() method to create a preview of selected file.
addstudent.component.ts
- import {
- Component,
- OnInit,
- ChangeDetectorRef
- } from '@angular/core';
- import {
- Student
- } from './student';
- import {
- StudentdataService
- } from './studentdata.service';
- import {
- Router
- } from '@angular/router';
- @Component({
- selector: 'app-addstudent',
- templateUrl: './addstudent.component.html',
- styleUrls: ['./addstudent.component.css']
- })
- export class AddstudentComponent implements OnInit {
- model = {
- rno: 0,
- name: '',
- mobile_no: '',
- student_img: ''
- };
- path = '';
- public file_srcs: string[] = [];
- public debug_size_before: string[] = [];
- public debug_size_after: string[] = [];
- constructor(private changeDetectorRef: ChangeDetectorRef, private studata: StudentdataService, public _route: Router) {}
- ngOnInit() {}
- fileChange(input) {
- this.readFiles(input.files);
- }
- readFile(file, reader, callback) {
- reader.onload = () => {
- callback(reader.result);
- this.model.student_img = reader.result;
- console.log(reader.result);
- }
- reader.readAsDataURL(file);
- }
- readFiles(files, index = 0) {
-
- let reader = new FileReader();
-
- if (index in files) {
-
- this.readFile(files[index], reader, (result) => {
-
- var img = document.createElement("img");
- img.src = result;
-
- this.resize(img, 250, 250, (resized_jpeg, before, after) => {
-
- this.debug_size_before.push(before);
- this.debug_size_after.push(after);
-
-
-
- this.file_srcs.push(resized_jpeg);
-
- this.readFiles(files, index + 1);
- });
- });
- } else {
-
- this.changeDetectorRef.detectChanges();
- }
- }
- resize(img, MAX_WIDTH: number, MAX_HEIGHT: number, callback) {
-
- return img.onload = () => {
-
- var width = img.width;
- var height = img.height;
-
- if (width > height) {
- if (width > MAX_WIDTH) {
- height *= MAX_WIDTH / width;
- width = MAX_WIDTH;
- }
- } else {
- if (height > MAX_HEIGHT) {
- width *= MAX_HEIGHT / height;
- height = MAX_HEIGHT;
- }
- }
-
- var canvas = document.createElement("canvas");
-
- canvas.width = width;
- canvas.height = height;
- var ctx = canvas.getContext("2d");
- ctx.drawImage(img, 0, 0, width, height);
-
-
- var dataUrl = canvas.toDataURL('image/jpeg');
-
- callback(dataUrl, img.src.length, dataUrl.length);
- };
- }
- studentSubmit() {
- this.studata.addStudent(this.model).subscribe(
- (data: any) => {
- this._route.navigate(['/allStudent']);
- },
- function(error) {
- console.log(error);
- },
- function() {
- console.log("On Complete");
- });
- }
- }
In the above code, I have created the filechange method which will be fired when file is selected. I have created two more functions for resizing the file and converting the file to base 64. Finally, on clicking the "Add Student" button, I am submitting the data using post method and on success, it will navigate back to student display page.
students.component.html
- <div class="container">
- <div class="row"> <button (click)="addStudent()">Add Student</button> <br/>
- <table class="table">
- <thead>
- <th>RollNo</th>
- <th>Name</th>
- <th>Mobile Number</th>
- <th>Photo</th>
- <th>Action</th>
- </thead>
- <tbody>
- <tr *ngFor="let item of allStudent ">
- <td>{{item.rno}}</td>
- <td>{{item.name | uppercase}}</td>
- <td>{{item.mobile_no}}</td>
- <td><span class="thumbnail"><img src="http://localhost:3000{{item.student_img}}" height="150px" width="150px" /></span></td>
- <td><button (click)="delStudent(item)"><span class="glyphicon glyphicon-trash"></span></button> </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
In this HTML, I am displaying the list of all students.
students.component.ts
- import {
- Component,
- OnInit
- } from '@angular/core';
- import {
- Student
- } from './student';
- import {
- StudentdataService
- } from './studentdata.service';
- import {
- Router
- } from '@angular/router';
- @Component({
- selector: 'app-students',
- templateUrl: './students.component.html',
- styleUrls: ['./students.component.css']
- })
- export class StudentsComponent implements OnInit {
- allStudent: Student[] = [];
- constructor(private _studata: StudentdataService, private _route: Router) {}
- ngOnInit() {
- this._studata.getAllStudent().subscribe(
- (data: Student[]) => {
- this.allStudent = data;
- },
- function(error) {
- console.log(error);
- },
- function() {
- console.log("complete");
- });
- }
- addStudent() {
- this._route.navigate(['/addStudent']);
- }
- delStudent(item: Student) {
- this._studata.deleteStudent(item).subscribe(
- (data: any) => {
- this.allStudent.splice(this.allStudent.indexOf(item), 1);
- },
- function(error) {
- console.log(error);
- },
- function() {});
- }
- }
The above code will loop through the "allStudent" array and display each and every student in HTML.
Add Student
Display Student
Conclusion
This tutorial is in continuation of my Angular 2 series. If you do not understand anything in this article, please go through the other parts of the tutorial. For example, if you are wondering how routing is done, then you can simply find everything here.