Getting this error while choosing image file
import {Injectable} from '#angular/core';
#Injectable()
export class UploadPhotoService {
filesToUpload: Array<File>;
constructor() {
this.filesToUpload = [];
}
upload() {
this.makeFileRequest("rest/api/upload", [], this.filesToUpload).then((result) => {
console.log(result);
}, (error) => {
console.error(error);
});
}
fileChangeEvent(fileInput: any){
this.filesToUpload = <Array<File>> fileInput.target.files;
}
makeFileRequest(url: string, params: Array<string>, files: Array<File>) {
return new Promise((resolve, reject) => {
var formData: any = new FormData();
var xhr = new XMLHttpRequest();
for(var i = 0; i < files.length; i++) {
formData.append("uploads[]", files[i], files[i].name);
}
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert("Upload successful!");
} else {
reject(xhr.response);
}
}
}
xhr.open("POST", url, true);
xhr.setRequestHeader("Authorization", "Bearer "+localStorage.getItem("token"));
xhr.send(formData);
});
}
}
<div class="field">
<label>Upload Photo</label>
<input type="file" (change)="uploadPhotoService.fileChangeEvent($event)" />
<button type="button" (click)="uploadPhotoService.upload()" class="ui mini button">Upload</button>
</div>
After choosing image file it showing the above error , Is there any other way to upload image file in angular2.. Please help on that too, and its giving EXCEPTION: Error in ./AddAdvertComponent class AddAdvertComponent - inline template:30:2 caused by: Cannot read property 'fileChangeEvent' of undefined
ORIGINAL EXCEPTION: Cannot read property 'fileChangeEvent' of undefined
throwing error
ORIGINAL EXCEPTION: Cannot read property 'fileChangeEvent' of undefined
because you are calling fileChangeEvent not correctly or your uploadPhotoService have not definer, you have to call it like this
if the method is in the same class
<input type="file" (change)="fileChangeEvent($event)" />
or if your method is in some different class or in some service than make sure you initilize that service in the constructor like this
constructor(prive uploadPhotoService: UploadPhotoService) { }
than you are able to use like this
<input type="file" (change)="uploadPhotoService.fileChangeEvent($event)" />
Related
I'm making an React application that involves fetching an API. The code is below, but basically I'm fetching the data from the API and then mapping over it to present information about each character. It works with the class component, but I tried to change it to a function component and it no longer works. There is no error, it simply doesn't display anything.
From using console.log(), I know that I'm successfully getting the information into the "characters" variable from the API when using the function component, and from comparing the two applications and using console.log() on "this.state.characters" (class) and "characters" (function), I'm pretty sure that getting the exact same data, an array of like 660 of the characters from the show where each character's information is inside of an object. When I tried to add paragraph tags with {characters[0].name} inside of the function component, I got the error "TypeError: Cannot read property 'name' of undefined".
I don't know if it's because I messed up something stupid or because I don't understand something about some detail about the difference between class and function components, either is obviously very possible. Thank you for any help.
Here is the code from the class component:
import React, { Component } from 'react';
export class Body extends React.Component {
constructor(props) {
super(props);
this.state = {
characters: [],
nameInput: '',
locationInput: '',
loading: true
};
};
async componentDidMount() {
let url = 'https://rickandmortyapi.com/api/character/';
let array = [];
for (let i = 1; i < 34; i++) {
let response = await fetch(url);
let data = await response.json();
for (let j = 0; j < 20; j++) {
array.push(data.results[j]);
}
url = data.info.next;
}
this.setState({characters: array, loading: false}, () => console.log(this.state.characters));
}
readInput = (e) => {
this.setState({nameInput: e.target.value});
console.log(this.state.nameInput);
}
readLocationInput = (e) => {
this.setState({locationInput: e.target.value});
console.log(this.state.locationInput);
}
render() {
return (
<div className="all">
<h4>Search by name:</h4>
<input onChange={this.readInput} />
<h4>Search by location:</h4>
<input onChange={this.readLocationInput} />
<br />
<div className="row m-1">
{this.state.loading ? 'Loading can take a few seconds. Your Rick and Morty experience will be ready soon!' : this.state.characters.filter((item) => {
if (this.state.nameInput == "") {
return item;
} else {
if (item.name.toLowerCase().includes(this.state.nameInput.toLowerCase())) {
return item;
}
}
}).filter((item) => {
if (this.state.locationInput == "") {
return item;
} else {
if (item.location.name.toLowerCase().includes(this.state.locationInput.toLowerCase())) {
return item;
}
}
}).map((item, id) => {
return (
<>
<div className="col-md-4 border border-dark rounded" id="square">
<h2>{item.name}</h2>
<img src={item.image} className="border rounded" />
<h4>Location: {item.location.name}</h4>
<h4>Status: {item.status}</h4>
</div>
</>
)
})}
</div>
</div>
);
}
};
Here is the code from the function component:
import React, { Component, useEffect, useState } from 'react';
import logo from '../rickandmortylogo.png';
export const Body = () => {
const [characters, setCharacters] = useState([]);
const [nameInput, setNameInput] = useState('');
const [locationInput, setLocationInput] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
let url = 'https://rickandmortyapi.com/api/character/';
let array = [];
const fetchAPI = async () => {
for (let i = 1; i < 34; i++) {
let response = await fetch(url);
let data = await response.json();
for (let j = 0; j < 20; j++) {
array.push(data.results[j]);
}
url = data.info.next;
}
}
fetchAPI();
setCharacters(array);
setLoading(false);
}, []);
const readInput = (e) => {
setNameInput(e.target.value);
console.log(nameInput);
}
const readLocationInput = (e) => {
setLocationInput(e.target.value);
console.log(locationInput);
}
return (
<>
<div className="text-center">
<img src={logo} className="img-fluid" />
</div>
<h2>Click on a character here to add them to your favorites. Choose "Check Favorites" in the menu bar to see your favorites and "Search Characters" to come back.</h2>
<div className="all">
<h4>Search by name:</h4>
<input onChange={readInput} />
<h4>Search by location:</h4>
<input onChange={readLocationInput} />
<br />
<div className="row m-1">
{loading ? 'Loading can take a few seconds. Your Rick and Morty experience will be ready soon!' : characters.filter((item) => {
if (nameInput == "") {
return item;
} else {
if (item.name.toLowerCase().includes(nameInput.toLowerCase())) {
return item;
}
}
}).filter((item) => {
if (locationInput == "") {
return item;
} else {
if (item.location.name.toLowerCase().includes(locationInput.toLowerCase())) {
return item;
}
}
}).map((item, id) => {
return (
<>
<div className="col-md-4 border border-dark rounded" id="square">
<h2>{item.name}</h2>
<img src={item.image} className="border rounded" />
<h4>Location: {item.location.name}</h4>
<h4>Status: {item.status}</h4>
</div>
</>
);
})}
</div>
</div>
</>
);
};
I am having issues with refreshing a partial view after post. what I want is to post some files, after they are uploaded I want to refresh a partial view. on a different partial view I delete the item and it refreshes ok, but on this partial it doesn't work. I got to some point were I can see that the refresh method is called before the AddImages and i still can't figure it out why the method is called and the data does not update.
I tried several methods here is where I am now :
Partial View-
<div id="UploadImages">
<form asp-page-handler="AddImages" id="imageUploadForm" method="post" data-ajax="true" data-ajax-method="post" data-ajax-update="#ProductImages">
<div class="card-body">
<h3>Edit Product Images</h3>
<input asp-for="#Model" multiple="multiple" id="ctl_images" name="upload_file" class="form-control" onchange="preview_image();" />
</div>
<button class="btn btn-sm btn-primary d-none d-md-inline-block" type="submit" id="AddImages" onclick="clickbtn();">
Add
</button>
</form>
<div id="image_preview">
</div>
</div>
Scripts to preview the uploaded image and to post to the razor page without refreshing the page, just the form:
<script>
//preview Images to upload.
function preview_image() {
total_file = document.getElementById("ctl_images").files.length;
for (var i = 0; i < total_file; i++) {
$('#image_preview').append("<span class=\"pip\">" +
"<img class='img-preview' id='previmg" + i + "'src='" + URL.createObjectURL(event.target.files[i]) + "'>"
+ "<br/><button class=\"btn-close\" aria-label='Close'></button>" + "</span>");
$('.btn-close').click(function () {
$(this).parent(".pip").remove();
$('#previmg' + i).click(function () { (this).remove(); });
});
}
}
//Load multiple Images to product catalog.
function clickbtn() {
var files = document.getElementById('ctl_images').files;
var url = window.location.pathname + "?handler=AddImages";
formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("CatalogImages", files[i]);
}
jQuery.ajax({
type: 'POST',
url: url,
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function () {
document.getElementById("imageUploadForm").reset();
var prv= document.getElementById("image_preview");
prv.innerHTML = "";
//if (repo.status == "success") {
// alert("File : " + repo.filename + " is uploaded successfully");
//}
},
error: function () {
alert("Error occurs");
},
});
}
Page model :
public async Task<IActionResult> OnPostAddImagesAsync()
{
var pathCtl = Path.Combine(_webHostEnvironment.WebRootPath, "Images/CatalogImages");
//if (!ModelState.IsValid)
// return Page();
//CatalogImages = (IFormFileCollection)Request.Form["ctl_Images"].ToList();
try
{
ProductImages = new List<ProductImageViewModel>();
foreach (var image in CatalogImages)
{
var uniqueFileName = string.Concat(Guid.NewGuid().ToString(), image.FileName);
using var fileStream = new FileStream(Path.Combine(pathCtl, uniqueFileName), FileMode.Create);
var productImage = new ProductImageViewModel
{
ImageUrl = Path.Combine("Images/CatalogImages", uniqueFileName),
ProductId = Product.Id,
};
await image.CopyToAsync(fileStream);
ProductImages.Add(productImage);
}
foreach (var item in ProductImages)
{
await _productImageRepo.Add(item, User);
}
var result = await OnPostRefreshImagesAsync(Product.Id);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return Page();
throw ex;
}
}
public async Task<IActionResult> OnPostRefreshImagesAsync(int id)
{
var productImages = await _productImageRepo.GetByProductId(id);
var result = new PartialViewResult
{
ViewName = "~/Pages/Partials/_ProductImagesCardGroup.cshtml",
ViewData = new ViewDataDictionary<List<ProductImageViewModel>>(ViewData, productImages),
};
return result;
}
I ended up adding this code line to make it work. it seems posting questiosn here gives me inspiration.
$('#ProductImages').html(response);
//Load multiple Images to product catalog.
function clickbtn() {
var files = document.getElementById('ctl_images').files;
var url = window.location.pathname + "?handler=AddImages";
formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("CatalogImages", files[i]);
}
jQuery.ajax({
type: 'POST',
url: url,
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function (response) {
document.getElementById("imageUploadForm").reset();
var prv = document.getElementById("image_preview");
prv.innerHTML = "";
**$('#ProductImages').html(response);**
//if (repo.status == "success") {
// alert("File : " + repo.filename + " is uploaded successfully");
//}
},
error: function () {
alert("Error occurs");
},
});
I am using ExpressJS with EJS template view engine. I am trying to show an HTML file on the angular component, but the form tag and its child input tag do not work on the angular side. They show only label data.
On NodeJS
agreementController.js
exports.getAgreementHtml = async (request, response, next) => {
const params = request.query
let reqPath = path.join(__dirname, '../agreements');
var agreementObj = {
user: { email: "example#gmail.com" }
}
// render domestic rent html
ejs.renderFile(reqPath + '/domestic_rent.ejs', agreementObj, {}, function (err, str) {
if (err !== null) {
responseObj.status = errorCodes.DATA_NOT_FOUND
responseObj.message = language.getMessage('NO_RECORD_FOUND')
response.send(responseObj)
return
}
responseObj.status = errorCodes.OK
responseObj.data = str
response.send(responseObj);
return;
});
}
domestic_rent.js
<form>
<div class="form-group">
<p><%= user.email %></p>
<div class="col-sm-offset-2 col-sm-10">
<input type="text" class="form-control" id="inputEmail3" placeholder="test" required name="test">
</div>
</div>
</form>
On Angular 8 Side
agreement-show.component.ts
getAgreementData() {
const params = {
id: this.agreementId
};
this.agreementService.getAgreementHtml(params).subscribe(
(result) => {
console.log('result agreement data::: ', result);
if (result.status !== 200) {
this.commonService.change.emit({ status: 'error', message: 'unknown error' });
return;
}
this.someHtml = result.data;
return;
}, (error) => {
console.log('error', error)
this.commonService.change.emit({ status: 'error', message: error.message });
}
);
}
agreement-show.component.html
<div [innerHTML]="someHtml"></div>
Output Attachment
By using ElementRef function we can add html runtime.
Please use following step:
#ViewChild('showitems') showitems: ElementRef;
const elemt: HTMLElement = this.showitems.nativeElement;
this.someHtml = result.data;
elemt.innerHTML = this.someHtml;
I want to edit and show value in form when user is editing but its not working. Angular frontend is capturing the correct route but data is not getting fetched from backend and no api is getting called. The content is not shown on browser. I'm attatching the git repository link also in case if you want to take a look https://github.com/tridibc2/blog-admin-mean. The route to do the editing is http://localhost:4200/admin/blog and click on edit button. Below I'm attaching edit-blog.component.html code
<h3>Edit this blog</h3>
<div class="row" style="text-align:left">
<div class="col-md-12">
<form #createBlogForm="ngForm" (ngSubmit)="editThisBlog()">
<div class="form-group">
<label>Blog Title</label>
<input type="text" name="blogTitle" [(ngModel)]="currentBlog.title" #title="ngModel" class="form-control" placeholder="Enter blog Title"
required>
</div>
<div [hidden]="title.valid || title.pristine" class="alert alert-danger">
Blog Title is required
</div>
<div class="form-group">
<label>Description</label>
<input type="text" name="blogDescription" [(ngModel)]="currentBlog.description" #description="ngModel" class="form-control" placeholder="Enter Description"
required>
</div>
<div class="form-group">
<label>Enter the blog body</label>
<textarea name="blogBodyHtml" [(ngModel)]="currentBlog.bodyHtml" #bodyHtml="ngModel" class="form-control" rows="3" required></textarea>
</div>
<div class="form-group">
<label>Category</label>
<select [(ngModel)]="currentBlog.category" #category="ngModel" name="blogCategory" class="form-control" id="category" required>
<option *ngFor="let category of possibleCategories" [value]="category">{{category}}</option>
</select>
</div>
<button type="submit" class="btn btn-default" [disabled]="!createBlogForm.form.valid">Edit the blog</button>
</form>
</div>
</div>
</div>
edit-blog.component.ts
import { ActivatedRoute, Router } from '#angular/router';
import { BlogpostService } from 'src/app/client/blogpost.service';
import { ToastsManager } from 'ng6-toastr/ng2-toastr';
import { FormGroup, FormBuilder } from '#angular/forms';
#Component({
selector: 'app-edit-blog',
templateUrl: './edit-blog.component.html',
styleUrls: ['./edit-blog.component.css']
})
export class EditBlogComponent implements OnInit {
public currentBlog;
public possibleCategories = ["Comedy", "Action", "Drama", "Technology","Cooking","Travel"];
constructor(private blogpostService: BlogpostService, private _route: ActivatedRoute, private router: Router, public toastr: ToastsManager) { }
ngOnInit() {
console.log("blogedit ngOnInIt called");
let myBlogId = this._route.snapshot.paramMap.get('blogId');
console.log(myBlogId);
this.blogpostService.getSingleBlogInformation(myBlogId).subscribe(
data =>{
console.log(data);
this.currentBlog = data;
console.log(this.currentBlog);
},
error =>{
console.log("some error occured");
console.log(error.errorMessage);
})
}
public editThisBlog(): any {
this.blogpostService.editBlog(this.currentBlog.blogId, this.currentBlog).subscribe(
data =>{
console.log(data);
this.toastr.success('Blog Edited Successfully.', 'Success!');
setTimeout(() =>{
this.router.navigate(['/blog', this.currentBlog.blogId]);
}, 1000)
},
error =>{
console.log(error);
console.log(error.errorMessage);
this.toastr.error('Some Error Occured.', 'Oops!');
}
)
}
}
service code
import { catchError } from 'rxjs/operators';
import { HttpClient, HttpErrorResponse, HttpBackend, HttpParams } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { throwError } from 'rxjs';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
#Injectable({
providedIn: 'root'
})
export class BlogpostService {
public allBlogs;
public currentBlog;
errorData: {};
isLoggedIn = false;
public baseUrl = 'http://localhost:4000/api/v1/blogs';
constructor(private _http:HttpClient, private handler: HttpBackend) { }
public getAllBlogs(): any {
let myResponse = this._http.get(this.baseUrl + '/all').pipe(
catchError(this.handleError)
);
console.log(myResponse);
return myResponse;
}
public getSingleBlogInformation(currentBlogId): any {
let myResponse = this._http.get(this.baseUrl + '/view/' + currentBlogId).pipe(
catchError(this.handleError)
);
return myResponse;
}
public createBlog(blogData): any {
let myResponse = this._http.post(this.baseUrl + '/create', blogData);
return myResponse;
}
public deleteBlog(blogId): any {
let data = {}
let myResponse = this._http.post(this.baseUrl + '/' + blogId + '/delete', blogId);
return myResponse;
}
public editBlog(blogId, blogData): any {
let myResponse = this._http.put(this.baseUrl + '/edit' + '/' + blogId, blogData);
return myResponse;
}
public getUserInfoFromLocalStorage: any = () =>{
return JSON.parse(localStorage.getItem('userInfo'));
}
public setUserInfoInLocalStorage: any = (data) =>{
localStorage.setItem('userInfo', JSON.stringify(data))
}
public signinFunction(data): Observable<any>{
const params = new HttpParams()
.set('email', data.email)
.set('password', data.password)
return this._http.post(`${this.baseUrl}/login`, params);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(`Backend returned code ${error.status}, ` + `body was: ${error.error}`);
}
// return an observable with a user-facing error message
this.errorData = {
errorTitle: 'Oops! Request for document failed',
errorDesc: 'Something bad happened. Please try again later.'
};
return throwError(this.errorData);
}
}
node controller code for the edit api
BlogModel.findOne({ 'blogId': req.params.blogId }, (err, result) => {
if (err) {
console.log(err)
res.send(err)
} else if (result == undefined || result == null || result == '') {
console.log('No Blog Found')
res.send("No Blog Found")
} else {
result.views += 1;
result.save(function (err, result) {
if (err) {
console.log(err)
res.send(err)
}
else {
console.log("Blog updated successfully")
res.send(result)
}
});// end result
}
});
}
route
app.put(baseUrl+'/edit/:blogId',blogController.editBlog);
the data object is like this
{"title":"Blog Title 2 Custom","description":"Blog description 2 Custom","bodyHtml":"<h3>Heading of the body CUSTOM</h3><p>This is the first blog data getting uploaded n blog project</p>","views":5,"isPublished":true,"category":"tech","author":"Decardo","tags":["english movies, action movies, comedy"],"_id":"5e1120d223416207d8ae5e1b","blogId":"nbfO8hJp","created":"2020-01-04T23:33:38.000Z","lastModified":"2020-01-04T23:33:38.000Z","__v":0}
Just fix the path of edit button like this:
<a [routerLink]="['/admin/edit', blog.blogId]" class="btn btn-info btn-sm">Edit</a>
Forward on the API part your edit method is incomplete as you are not updating the object that you find with the new values.
let editBlog = (req, res) => {
const data = req.body;
BlogModel.findOne({ 'blogId': req.params.blogId }, (err, result) => {
if (err) {
console.log(err)
res.send(err)
} else if (result == undefined || result == null || result == '') {
console.log('No Blog Found')
res.send("No Blog Found")
} else {
for (let key in data) {
result[key] = data[key];
}
result.views += 1;
result.save(function (err, result) {
if (err) {
console.log(err)
res.send(err)
}
else {
console.log("Blog updated successfully")
res.send(result)
}
});// end result
}
});
};
To edit the Blog's info you are calling editBlog method from blogpost service passing into it an id (blogId) and a body (blogData). So on the server side what you get is an id and body which is the update data. You can get the body from request so req.body. What you missed is to update actually the object you found, and that's why i made a loop to update the values of Blog object with the new values from req.body, and only once updated you save it. Obviously there are other ways to update the object we want to modify.
I have a form like that in nuxt :
<v-form v-if="displayForm" ref="form" v-model="valid" enctype="multipart/form-data" lazy-validation>
<v-flex xs12 md6 sm12>
<v-text-field
v-model="linkOriginal"
label="Link to the original work (not required)"
/>
</v-flex>
<v-flex xs12 md6 sm12>
<span>Pic from original work (required)</span>
<input id="file" ref="file" type="file" #change="handleFileUpload()">
</v-flex>
</v-form>
And my script is like that :
<script>
export default {
data() {
return {
file: "",
linkOriginal: "",
};
},
methods: {
handleFileUpload() {
console.log(this.$refs.file.files[0]);
this.file = this.$refs.file.files[0];
},
submit() {
if (this.$refs.form.validate()) {
let formData = new FormData();
formData.append("file", this.file);
formData.append("notifDate", this.notifDate)
this.$axios
.post(
"http://mynodeserver.com:3000/infringement",
formData,
{
headers: {
"Access-Control-Allow-Origin": true
"Content-Type": "multipart/form-data"
}
}
)
.then(response => {
this.displayForm = false;
this.displayError = false;
this.displaySuccess = true;
})
.catch(e => {
this.displayForm = false;
this.displaySuccess = false;
this.displayError = true;
});
} else {
console.log("u need to complete the required elements");
}
},
clear() {
this.$refs.form.reset();
}
}
};
</script>
On my node server-side part when I console log req.body.file or req.body.notifDate it returns undefined so I can't attach it to the email I want to send with nodemailer. what am I missing here?
The axios.post() request is taking an object as a second parameter, axios.post('/api/submit', {data: formData})