What I am doing:
I am displaying an image from image file using mongodb database, nodejs and angular 4. The image is displayed well.
Problem:
The path of the image that I am showing is assets/Images/1.jpg
. This path comes from database.
Now, I go to the folder assets/Images
and delete 1.jpg. Then I upload a new Image to this folder and then I rename that newly uploaded image to 1.jpg.
But the browser is still displaying old image.
What I tried:
I tried to refresh the browser tab. But still it is displaying the old image.
So, as mentioned in this post, I tried empty cache and hard reload
. Still the browser is displaying the old Image.
Then I restarted the server. And as expected browser shows me the new Image.
What I want:
I want that the browser should immediately show me the changed Image as soon as I copy-paste new Image, delete the old one and rename the new image.
If a sudden change is not possible, then I want the browser to display new Image when page is refreshed programatically.
Sample that reproduces issue
You can download the sample at this link: https://drive.google.com/file/d/0B5WyqSALui0bekJhTGtudWNOd28/view?usp=sharing
How to use sample to run the app
- Download the sample files from above mentioned link.
- Extract the file.
- open git bash or terminal and navigate to
image-sample
folder - run
npm install
command. - After dependencies are installed,
cd node-files
, thencd seed
- run
node image-seeder
command. This will create a sample database in mongodb and then insert sample data. - run
cd ..
twice to come to the original folder and then - run the application by
npm start
- open browser and type
localhost://3000
in the address bar. You should see the image. - Now browse src/assets/Images folder
- Delete 1.jpg
- Rename 2.jpg to 1.jpg and then look at the browser. The image will not be changed.
- Refresh the browser window. Still Old Image will be shown.
- Restart the server and then you can see the changed Image.
Code and Description
First I created the angular app using
ng new image-sample
Then I added some dependencies in package.json as follows:
"body-parser": "^1.17.1",
"cookie-parser": "^1.4.3",
"core-js": "^2.4.1",
"express": "^4.15.2",
"fs": "0.0.1-security",
"mongoose": "^4.9.9",
"morgan": "^1.8.1",
"path": "^0.12.7"
I also changed the scripts as follows:
"scripts": {
"ng": "ng",
"start": "npm run serve-build",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"build:nodeserver": "ng build && cp nodeserver/* dist",
"build:nodeserver-prod": "ng build -prod && cp nodeserver/* dist",
"serve-build": "npm run build:nodeserver && cd dist && node server.js",
"serve-build-prod": "npm run build:nodeserver-prod && cd dist && node server.js"
},
Then I install these dependencies using:
npm install
Then I created some folders and files in image-sample
directory as follows:
nodeserver
|-- server.js
node-files
|--models
|-- db.js
|-- Image.js
|--api
|-- image.js
|--seed
|-- image-seeder.js
Here is the content of above mentioned files:
nodeserver/server.js
var express = require('express');
var morgan = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var path = require('path');
var fs = require('fs');
require('../node-files/models/db');
var image = require('../node-files/api/image');
var app = express();
var staticRoot = __dirname + '/';
app.set('port', (process.env.PORT || 3000));
app.use(express.static(staticRoot));
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(function(req, res, next){
// if the request is not html then move along
var accept = req.accepts('html', 'json', 'xml');
if(accept !== 'html'){
return next();
}
// if the request has a '.' assume that it's for a file, move along
var ext = path.extname(req.path);
if (ext !== ''){
return next();
}
fs.createReadStream(staticRoot + 'index.html').pipe(res);
});
app.use('/api/image', image);
app.listen(app.get('port'), function() {
console.log('app running on port', app.get('port'));
});
node-files/models/db.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/sampleimagedb')
node-files/models/Image.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var imageSchema = new Schema({
url: {type: String, required: true},
width: {type: Number, required: true},
height: {type: Number, required: true}
});
var Image = module.exports = mongoose.model('Image', imageSchema);
module.exports.getAllImages = function(callback){
Image.find().lean().exec(function(err, images){
if (err) return callback(err, null);
callback(null, images);
});
};
node-files/api/image.js
var express = require('express')
var router = express.Router();
var Image = require('../models/Image');
router.get('/', function(req, res, next) {
Image.getAllImages(function(err, images) {
if(err) { return res.status(400).json(err); }
else { res.status(200).json(images); }
});
});
module.exports = router;
node-files/seed/image-seeder.js
var Image = require('../models/Image');
var mongoose = require('mongoose');
mongoose.connect('localhost:27017/sampleimagedb');
var images = [
new Image({
url: 'assets/Images/1.jpg',
width: 300,
height: 200
})
];
var done = 0;
for(var i = 0; i < images.length; i++)
{
images[i].save(function(err, result){
done++;
if(done == images.length){
exit();
}
});
}
function exit() {
mongoose.disconnect();
console.log(images.length + ' Image(s) added to the database');
}
And then on angular side, I created a folder called models
under src/app
. In which I added Image.ts
file which looks like:
export class Image
{
url: string;
height: number;
width: number;
constructor(url: string, height: number, width: number) {
this.url = url;
this.height = height;
this.width = width;
}
}
I created a services
folder inside src/app
folder. Then I added a service called ImageService
in services folder using angular-cli tool as follows:
ng g service image
That generates two files, one of them is image.service.ts
which looks like:
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import { Image } from '../app.component';
@Injectable()
export class ImageService {
constructor(private http:Http) { }
public image: Image
getImages(): Observable<Image[]> {
return this.http.get('/api/image')
.map(res => res.json());
}
}
Then I added this service in the providers section of app.module.ts
which looks like:
providers: [ImageService],
Then in the app.component.ts
file I call the ImageService
as follows:
import { Component, OnInit } from '@angular/core';
import { ImageService } from './services/image.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
images: Image[];
ngOnInit() {
this.imageService.getImages()
.subscribe(
response => this.images = response,
error => console.log(error)
);;
}
constructor(private imageService: ImageService) {
}
}
And finally in app.component.html
:
<div *ngFor="let image of images">
<img [src]="image.url" style="left:0px;top:0px;"
[style.width.px]="image.width" [style.height.px]="image.height"/>
</div>
via Vishal
No comments:
Post a Comment