Handling file upload in Sharepoint List with React form - javascript

I am creating a form webpart with react but I am stuck at uploading a file, So I want to upload a file when it hit submit button and that has to create sharepoint list item with attachment file.
above image is for reference to understand.
Now I am able to create Above two Subjects and comments in sharepoint list but unsure for upload to attach with same list item as attachments.
<div className={styles.row}>
<ReactFileReader fileTypes={[".csv", ".xlsx", ".Docx", ".pdf"]} base64={true} handleFiles={this.handleFiles.bind(this)}>
<button className='btn' value={this.state.UploadedFilesArray.toString()} >Upload</button>
</ReactFileReader>
</div>
<div className={styles.row}>
<div >
<button id="btn_add" className={styles.button} onClick={this.createItem.bind(this)}>Submit</button>
</div>
The above code is for Upload and Submit, As I said I want to attach the attachment when I submit the form.
private createItem(): void {
this.setState({
status: 'Creating item...',
items: []
});
const body: string = JSON.stringify({
'Title': this.state.subject,
'Comments': this.state.comments,
});
this.props.spHttpClient.post(`${this.props.siteUrl}/_api/Web/lists/getbytitle('${this.props.listName}')/items`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
//"Accept": "application/json; odata=verbose",
'Content-type': 'application/json;odata=nometadata',
'odata-version': ''
},
body: body
})
.then((response: SPHttpClientResponse): Promise<IListItem> => {
return response.json();
console.log(response)
})
.then((item: IListItem): void => {
this.setState({
status: `Item '${item.Title}' (ID: ${item.Id}) successfully created`,
items: []
});
}, (error: any): void => {
this.setState({
status: 'Error while creating the item: ' + error,
items: []
});
});
}
The above code is for handling the submit, Now can anyone help me creating the handle file function with the functionality that I want to create a sharepoint list item with an attachment when I hit the Submit button. Also with Success or Error message.

I suggest you use this awesome library PNPJS library, it will be easy to work with attachments.
Use (PnPJS) library with SharePoint Framework web parts
Add attachments after item created
private handleFiles(f) {
var filelist = f.fileList;
var fileInfos: IAttachmentFileInfo[] = [];
fileInfos.push({
name: "My file name 1",
content: "string, blob, or array"
});
// loop through files
for (var i = 0; i < filelist.length; i++) {
// get item
let file: File = filelist.item(i);
fileInfos.push({
name: file.name,
content: file
});
}
this.setState({
uploadfiles: fileInfos
});
}
private createItem(): void {
sp.web.lists.getByTitle("mylist").items.add({
'Title': this.state.subject
}).then((r: IItemAddResult) => {
r.item.attachmentFiles.addMultiple(this.state.uploadfiles);
}).then(e => {
console.log("successfully created");
}).catch(e => {
console.log("Error while creating the item" + e)
});
}
For more details, please refer to below demo:
SharedSPFx

Related

Angular search by clicked tag

In my app I am trying to make a feature that when the user click the tag it shows him all the products that have this tag...
My search request is being made with GET method over an API call... so what I am trying to achieve is that on a tag click the tag value is sent as a parameter in the url and thus returning all products with this tag in a new page... My API call works in POSTMAN but I am having trouble implementing it in Angular...
So my main questions and issues are:
How to make the tag clickable so it sends the value with the api request
How to add routerlink to the tag so it redirects to new page where it shows all the products with this tag
I am very new to Angular so please help :)
This is the image how tags are displayed in the app:
Here is my code:
HTML in home.page.html for outputing the tags:
<ion-chip *ngFor="let tag of tags">
<ion-label>{{ tag.tags }}</ion-label>
</ion-chip>
Code for search API in search.service.ts:
searchByTagCall(tag: string) {
return from(Preferences.get({key: 'TOKEN_KEY'})).pipe(
switchMap(token => {
const headers = new HttpHeaders().set('Authorization', `Bearer ${token.value}`);
let params = new HttpParams();
params = params.append('tag', tag);
return this.httpClient.get(`${environment.apiUrl}search`, {headers, observe: 'response', params});
}),
catchError(err => {
console.log(err.status);
if (err.status === 400) {
console.log(err.error.message);
}
if (err.status === 401) {
this.authService.logout();
this.router.navigateByUrl('/login', {replaceUrl: true});
}
return EMPTY;
}),
);
}
Code of home.page.ts:
searchByTag() {
this.searchService.searchByTagCall(tag).subscribe(
(data: any) => {
/* what do I put here? */
},
error => {
console.log('Error', error);
});
}
My JSON looks like this:
{
"tags": [
{
"tags": "fruit"
},
{
"tags": "sour"
},
{
"tags": "sweet"
},
{
"tags": "frozen"
},
{
"tags": "fresh"
},
{
"tags": "vegetable"
},
{
"tags": "raw"
}
]
}
Do the following changes:
home.page.html:
<ion-chip *ngFor="let tag of tags">
<ion-label class="tag" (click)="searchByTag(tag.tags)">{{ tag.tags }}</ion-label>
</ion-chip>
home.page.scss:
// In case you need to change the cursor to be the hand icon
.tag {
cursor: pointer;
}
home.page.ts:
constructor(/*whatever parameters you have in your constructor already*/, private router: Router, private dataService: DataService) {
// Whatever code you have in your constructor
}
searchByTag(tag: string) {
this.searchService.searchByTagCall(tag).subscribe((data: any) => {
// 1. Store the data in some service so it will be accessible for the other page
this.dataService.tagData = data;
// 2. Navigate to the other page (you can store the tag in the route params if you need it)
this.router.navigate(['/tagPage/', tag]);
},
error => {
console.log('Error', error);
});
}

I get undefined when i try to add an Object from an api to my mongodb atlas db NODE JS

I get a list of pokemons from a third party API. I want to add specific ones to a favorites list when I click the add button. but whenever I try to render the list of favourite pokemon i just get objects saying undefined.
Any help would be appreciated.
//Here i try to add the fetched object to my rest api//
function createPokemonCard(data) {
const pokeContainer = document.getElementById("poke-container");
const pokemonEl = document.createElement('div');
pokemonEl.classList.add('pokemon');
const pokeInnerHtml = `
<div class="img-container">
<img src="${data.sprites.front_default}">
</div>
<div class="pokeCard">
<h1 id="id">${data.id}</h1>
<h3 id="name">${data.name}</h3>
<h4 id="type">${data.types.map(type => type.type.name).join(", ")}</h4>
<button onclick="addFavourite()">Add</button>
</div>
`;
pokemonEl.innerHTML = pokeInnerHtml;
pokeContainer.appendChild(pokemonEl);
}
// i am trying to get the value//
async function addFavourite() {
let name = document.getElementById('name').value ;
let type = document.getElementById('type').value ;
let data = {
"name": name,
"type": type
}
await fetch('https://web2-course-project-api-somrad.herokuapp.com/api/pokemons', {
method: "POST",
mode: 'cors',
headers: {
'Content-type': 'application/json; charset=utf-8'
},
body: JSON.stringify(data)
});
}
// my back end post request//
pokemonRouter.route('/pokemons')
//POST YOUR FAVOURITE POKEMON
.post((req, res)=>{
const collection = db.collection("pokedex");
collection.insertOne(req.body).then(
() => {
res.status(200).json({
message: 'Added!'
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
});
})
this is my collection, the first three entries is added manually
The list probably prints "undefined" since some of the objects provided by the database don't have a name.
[
{"_id":"610d3316bf52a4e260126877","name":"Pikachu","type":"Electric"},
{"_id":"610e689defe3ad8654648ec3","name":"Charmander","type":"Fire"},
{"_id":"610e68acefe3ad8654648ec4","name":"Bulbasaur","type":"Grass"},
{"_id":"6118df7554b38705559eaacd"},
{"_id":"6118f0e493b20fefb0fd1689"},
{"_id":"6118f1e7128dd43ee68f8140"},
{"_id":"6118f2e8128dd43ee68f8141","name":"test","type":"grass"},
{"_id":"6118f57a128dd43ee68f8142"},
{"_id":"6118f5ca128dd43ee68f8143"},
{"_id":"6118f6a6128dd43ee68f8144"},
{"_id":"6118f6da128dd43ee68f8145"},
{"_id":"6118f6fd128dd43ee68f8146"},
{"_id":"6118f86f128dd43ee68f8147"},
{"_id":"6118f8e4128dd43ee68f8148"},
{"_id":"6118f924128dd43ee68f8149"},
{"_id":"6118fb34128dd43ee68f814a"}
]
This already includes my other suggestions.
I recommend that you filter out the invalid ones before rendering the rest.
// your list with the pokemon before you create the html elements
// this simply removes all pokemon from the list that don't have a name or type
const yourList = [];
const yourFilteredList = yourList.filter(item => {
if(item.name === undefined) return false;
if(item.type === undefined) return false;
return true;
})
Please also note that in mongoDB the Primary Key of the database is _id not id
<h1 id="id">${data._id}</h1>
This could also be an issue, since the type field of the API you provided is a string not a list as indicated. This may result in an Uncaught TypeError: something.join is not a function
<h4 id="type">${data.types.map(type => type.type.name).join(", ")}</h4>

Change data in DOM after successful fetch PUT

I have an SPA in vanilla JS, using classes and modules.
The main idea is creating visits of customers and render them. When I fill in the form, data are sent to the server in JSON, after successful fetch, a visit card is created in the #content section.
The rendered card has two options: edit and delete. I made deletion without problems, I send DELETE, then just remove() the element onclick.
But I have some difficulties when editing the card.
I wrote the code to pop up modal form when click on the Edit button, and this form is filled with the card's data, so that the user can change them, click on Submit and send PUT to the server. The response is successful.
This is the edit form submit
edit(id) {
const readData = document.querySelector('.form-edit');
readData.addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Array.from(formData.entries()).reduce((memo, pair) => ({
...memo,
[pair[0]]: pair[1],
}), {});
editCard(data, id)
.then((response) => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong');
}
})
document.querySelector(".closeBtnEdit").click();
});
}
What I want, is to change the info of existing card in DOM after submitting the edited data.
This is the code of card rendering:
render(parent){
this.elem.fullName.textContent = this.fullName;
this.elem.purpose.textContent = `Purpose of the visit: ${this.purpose}`;
this.elem.desc.textContent = `Description: ${this.desc}`;
this.elem.priority.textContent = `Priority: ${this.priority}`;
this.elem.date.textContent = `Visit Date: ${this.date}`;
this.elem.delBtn.textContent = `Delete`;
this.elem.editBtn.textContent = `Edit`;
}
Edit card API:
function editCard(newCard, cardId) {
return fetch(`${API}/${cardId}`,{
method: "PUT",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newCard)
})
}

Can't access to Object Value

I'm building my React Component and got this error when I tried to use a axios request and add that response data to an object. But when I tried to console.log the object, it showed me the value when I expanded the object, but still display null.
let id, title, channel;
let details = {
timestamp: null,
views: null,
likes: null,
description: null
};
if (active == undefined) {
active = {};
} else {
id = active.id;
title = active.title;
channel = active.channel;
let dataObject = API.get(`videos/${id}`, {
params: {
api_key: "ab4d78b8-e8ff-4392-bff8-21d1058cd420"
}
});
dataObject.then(result => {
let data = result.data;
details.timestamp = data.timestamp;
details.views = data.views;
details.likes = data.likes;
details.description = data.description;
});
}
return (
<div className="videoContent">
<h1 className="videoContent__title">{title}</h1>
<div className="videoContent__details">
<div className="videoContent__details--user">
<p className="channel">By {channel}</p>
<p className="timestamp">{dateFormat(details.timestamp)}</p>
</div>
<div className="videoContent__details--social">
<p className="views">
<img src={viewIcon} alt=""></img>
{/* {details.views} */}
</p>
<p className="likes">
<img src={likeIcon} alt=""></img>
{/* {props.details.likes.toLocaleString()} */}
</p>
</div>
</div>
<div className="videoContent__description">
{/* <p>{details.description}</p> */}
</div>
</div>
);
}
And this is what I got from the console:
{
timestamp: null,
views: null,
likes: null,
description: null
}
timestamp: 1537003624000
views: "2,043,765"
likes: "400,058"
description: "Luxury is something everyone deserves from time to time. Such
an indulgence can make a vacation a truly rejuvenating experience. This video will
focus a lot on helping the first time or inexperienced traveler head out prepared and
confident in themselves."
__proto__: Object
Edit: My axios call:
import axios from "axios";
export default axios.create({
baseURL: "https://project-2-api.herokuapp.com/",
responseType: "json"
});
JavaScript is always synchronous and single-threaded. If you're executing a JavaScript block of code on a page then no other JavaScript on that page will currently be executed.
JavaScript is only asynchronous in the sense that it can make, for example, Ajax calls. The Ajax call will stop executing and other code will be able to execute until the call returns (successfully or otherwise), at which point the callback will run synchronously. No other code will be running at this point. It won't interrupt any other code that's currently running.
to solve your problem you should use promises or Async/await,try to modify your code like below:
let dataObject = () => {
return new Promise((resolve, reject) => {
API.get(`videos/${id}`, {
params:{
api_key: "ab4d78b8-e8ff-4392-bff8-21d1058cd420"
}
}, function(error, response, data){
if (error) reject(error);
let content = JSON.parse(data);
let result = content.value;
resolve(result);
})
}
);
};
dataObject(url)
.then(result => {
let data = result.data;
details.timestamp = data.timestamp;
details.views = data.views;
details.likes = data.likes;
details.description = data.description;
return (<div>...</div>)
})
.catch(err => {
console.(error)
});

PDF in iframe showing title as 'Anonymous'

I am using Angular2. I am getting PDF response as BLOB from backend API. The PDF is showing fine in iframe but it is showing title as 'anonymous'. Can someone please guide?
html code:
<iframe id="showPDFIframe" allowtransparency="false" title="TestPDF" width="100%" height="800" [attr.src]="dataLocalUrl" type="application/pdf"></iframe>
pdf.component.ts
pdfDownload: any;
protected dataLocalUrl: SafeResourceUrl;
ngOnInit() {
this.requestOptions = this.createRequestOptions();
this.requestOptions.responseType = ResponseContentType.Blob;
this._pdfModelService.showPDF(this.requestOptions)
.subscribe( (res) => {
this.pdfDownload = res;
this.dataLocalUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(res));
}, err => {
console.log(err);
})
}
pdfModelService.ts
showPDF(options?: RequestOptions): any {
return this._http.get(this.endpoints.showPDF.uri, options)
.map( (res) => {
return new Blob([res], { type: 'application/pdf' })
});
}
See below image 'Anonymous' is showing
Note: backend API gives the bytes which we cast in BLOB.
have you tried providing title in the options:
showPDF(options?: RequestOptions): any {
return this._http.get(this.endpoints.showPDF.uri, options)
.map( (res) => {
return new Blob([res], { type: 'application/pdf', title: 'testpdf' })
});
}
Although I am not certain why the specified title field "TestPDF" in the code is not appearing on the page, the "(anonymous)" value that is displaying could simply be pulling the meta data from the PDF file itself. A possible solution would be to check the title field in the PDF document properties to set the title there. In Adobe Acrobat, from the file menu select Properties > Description to check/update the title field.
Reference article from W3.org: https://www.w3.org/TR/WCAG20-TECHS/PDF18.html

Categories