How can I retrieve a SharePoint list items attachments using spfx? - sharepoint-online

I've managed to figure out how to submit multiple attachments to a sharepoint list item.
I now need to retrieve the item and display these items in the same form that was submitted.
Here's the submit code:
private _onSubmit() {
this.setState({
FormStatus: 'Submitted',
SubmittedLblVis: true,
}, () => {
pnp.sp.web.lists.getByTitle("My List").items.add({
State: this.state.State,
State1: this.state.State1,
}).then((iar: ItemAddResult) => {
var attachments: AttachmentFileInfo[] = [];
attachments.push({
name: this.state.FileUpload[0].name,
content: this.state.FileUpload[0]
});
attachments.push({
name: this.state.FileUpload2[0].name,
content: this.state.FileUpload2[0]
});
attachments.push({
name: this.state.FileUpload3[0].name,
content: this.state.FileUpload3[0]
});
iar.item.attachmentFiles.addMultiple(attachments);
This works great.
I have a button the form that allows the user to read an item and populate all the fields in the form. This works fine. But it's not working for the attachments. First thing is I don't know what the Attachments column is called!
Here's the retrieval function:
private _editItem = (ev: React.MouseEvent<HTMLElement>) => {
const sid = Number(ev.currentTarget.id);
let _item = this.state.Items.filter((item) => { return item.Id === sid; });
if (_item && _item.length > 0) {
this._getListItems();
this.setState({
State etc...with a few examples
FormStatus: _item[0].FormStatus,
showModal: true
//The below callback function
}, () => {
if (_item[0].PanelMember) {
this.PanelMemberGetPeoplePicker(Number(_item[0].PanelMemberId));
}
});
}
}
And the _getListItems() function within the above:
public _getListItems() {
sp.web.lists.getByTitle("MyList").items.get().then((items: any[]) => {
let returnedItems: MyDataModel[] = items.map((item) => { return new MyDataModel(item); });
this.setState({ Items: returnedItems });
});
}
I understand that I'll have to update the MyDataModel interface with whatever the attachment column is but what is the attachment column? And how would I implement it within the above to retrieve all 3 attached documents?

Get the item first, then get item attachment files.
let item=sp.web.lists.getByTitle("TestList").items.getById(13);
item.attachmentFiles.get().then((files)=>{
console.log(files);
})

Related

How to get a specific data from object of array in angular

I wanna know that how to get the data
HERE IS MY node.js
app.post('/pathname', function (req, res){
fs.readfile('filepath', 'utf8', function(err, data){
if(data){
let valueofdata = JSON.parse(data);
let anothervalue = JSON.stringify(valueofdata[0]);
res.send(anothervalue);
}
My JSON file is
[{
"number":[{
"data":"one",
"data":"two",
"data":"three"
}],
"number1":[{
"data":"four",
"data":"five",
"data":"six"
}],
}]
My ANGULAR file
numberval:any;
ngOnInit(): void {
this.numberval = this.service.numbervalueall; --> the value (number) is stored in service
console.log(this.numberval)
}
numberall(data:any){
this.http.post('http://localhost:4001/pathname', data, {responseType : "text"} )
.subscribe(res => {
console.log(res)
this.numbersname = JSON.parse(res) --> Data from node.js is stored in here
console.log(this.numbersname )
})
}
numbersname!:any;
numberdata(){
this.numberall(this.service.numbervalueall)
}
sampledata(){
console.log(this.service.citydata)
setTimeout(() => {
this.numberall(this.service.citydata)
console.log(this.hotelvalue)
},100);
}
How can I get the specific value from object data stored in res I used res.this.service.numbervalueall but can't get the value. Please Help me with this.
In your ANGULAR file
create new variable as datavalue or your choice
datavalue:any;
numberall(data:any){
this.http.post('http://localhost:4001/pathname', data, {responseType : "text"} )
.subscribe(res => {
console.log(res)
this.numbersname = JSON.parse(res)
this.datavalue = this.numbersname[numbervalueall] --> here u get the specific data in datavalue
})
}

Best way to access data in react

PROBLEM:
I have a MERN application that is has a model with a couple of other models in it. The problem that I figured out later is that it saves the _id of the object and not the actual object in the model when you do this
const checkoutHistory = new Schema({
book: { type: mongoose.Schema.Types.ObjectId, ref: 'books',required: true },
checkoutCopiesNum: {type: Number, required: true},
profChosen: { type: mongoose.Schema.Types.ObjectId, ref: 'prof', required: true },
dueDate: {type: String, required: true}
})
The book: part of the object when retreived will be an id some string like "DKKLDFJhdkghhe839kdd" whatever. This is fine because then I guess I can make an API call in the react app later to search for this book. Is this the correct way to do it though?
The other way that I thought of was in the actual endpoint that retrieves the data was to call the findByID functions and set that data. It didn't work though here is the code for that:
const checkoutHistoryMiddle = async (req, res, next) => {
try {
//get the body of the request
const body = req.body
//check for data
if(!body){
return res.status(400).json({
success: false,
error: 'no body given'
})
}
const history = new CheckoutHist(body)
console.log(history)
// await Book.findById({_id: history.book}, (err, book) => {
// history.book = book
// })
// await Prof.findById({_id: history.profChosen}, (err, prof) => history.profChosen = prof)
console.log(history)
history.save().then(() => next()).catch(error => {
return res.status(400).json({
success: false,
message: error,
msg: "checkout save failed"
})
})
} catch (error) {
res.status(400).json({
success: false,
message: error,
msg: "checkoutHist failed"
})
}
}
I commented out the part I was talking about because well, it didn't work. It still saved the id instead of the object. Which like I said is fine. I gave my other idea a go and decided to do the calls inside the react app.
So I first got the array of objects from the schema provided above like this:
const [bookHist, setBookHist] = useState()
useEffect( () => {
const getHistory = async () => {
api.getCheckoutHist().then(hist => {
setBookHist(hist.data.data.filter((data) => data.book === props.book_id))
})
}
getHistory()
}, [])
This will create an array of objects in bookHist that looks like this
[{_id: "DKJFDKJDKLFJSL", book: "LDKhgajgahgelkji8440skg", checkoutCopiesNum: 3, profChosen: "gjellkdh39gh39kal930alkdfj", dueDate: "11/11/11"}, {...}]
so the next step would be to take each item in the array and get the id to search the database with so api.findProfByID(bookHist[0].profChosen)
then I would need to update the state of bookHist somehow only that item without effect the other items in the array.
The questions I have are what is the best way to update one item in the array state?
How do I make so many api calls? how do I make sure that they are waited on so that the state actually changes once the calls complete?
Here are things I have tried so far:
useEffect(() => {
bookHist.map(async bHist => {
await Axios.get("http://localhost:8174/user/professor/" + bHist.profChosen).then(async prof => {
// console.log(prof)
// console.log(prof)
bHist.profChosen = prof.data.data
// setBookHist(prevStat => ({}))
// setBookHist(...bookHist, [bookHist.])
})
setBookHist(bHist)
})
}, [])
this didn't work I assume because it would not update the state because it is not waiting on the map to finish before it sets the state of bookHist
So then I searched on the internet and found a promisAll method in react like this:
useEffect(() => {
const change = async () => {
if(bookHist){
console.log("prof")
//get the prof data
// const galleries = []
await Promise.all(bookHist.map( (bHist, index) => {
return await Axios.get("http://localhost:8174/user/professor/" + bHist.profChosen);
})).then(someData => {
console.log(someData)
});
}
change()
}, [])
This also does not work for unknown reasons. It only works if it hot reloads and does not refresh. The logging actually logs something when it hot refreshes.
here is the entirety of the funcitional component:
import React, {useState, useEffect} from 'react'
import api from '../../api/index'
import Axios from 'axios'
export default function CheckoutBookHistroy(props){
const [bookHist, setBookHist] = useState()
const [histData, setHistData] = useState([{
book: {},
prof: {}
}])
useEffect( () => {
const getHistory = async () => {
api.getCheckoutHist().then(hist => {
setBookHist(hist.data.data.filter((data) => data.book === props.book_id))
})
}
getHistory()
}, [])
//i also tried this way but this resulted in an infinite loop
const [profChosen, setProfChosen] = useState()
const handleProfFind = async (id) => {
await Axios.get("http://localhost:8174/user/professor/" + id).then(prof => {
setProfChosen(prof.data.data)
})
}
return (
<div>
{
bookHist ?
bookHist.map(data => {
//need to present the prof data here for each data obj
return (
<div>Checked out {data.checkoutCopiesNum}</div>
)}) : <div>no data</div>
}
</div>
)
}
I really hope I can gain some insight into the correct way to do all of this. I must be either really close or awfully wrong. Thank you in advance!
just by looking at your code, i don't see too much issue, although your code is a bit convoluted.
some functions has no caller, ex. handleProfFind. One suggestion, if you want to do something, just do it, no need that many functions, ex.
// assume you only want to do it once after mounting
useEffect( () => {
if (!data) {
api.getCheckoutHist().then(hist => {
// you can set your data state here
// or you can get the id inside each item, and then call more APIs
// whatever you want to do, please finish it here
}
}
}, [])

How to read unread email with body and attachment using node-ews package

I am able to send email using this node-ews package but I am not able find suitable example to read email from Inbox folder and get the body and attachments from the email.
I have gone through the Microsoft docs e.g. https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-work-with-exchange-mailbox-items-by-using-ews-in-exchange#get-an-item-by-using-the-ews-managed-api
but the examples are provided in C#, C++ or VB..
But I want to do this with Nodejs.
You can use following code to get emails from Inbox using FindItem function and then read each email using GetItem function
// Read emails from Inbox
var ewsFunction = 'FindItem';
var ewsArgs = {
'attributes': {
'Traversal': 'Shallow'
},
'ItemShape': {
't:BaseShape': 'IdOnly',
't:AdditionalProperties': {
't:FieldURI': {
'attributes': {
'FieldURI': 'item:Subject'
}
}
}
},
'ParentFolderIds' : {
'DistinguishedFolderId': {
'attributes': {
'Id': 'inbox'
}
}
}
};
// Itreate over all the emails and store Id and ChangeKey.
ews.run(ewsFunction, ewsArgs, ewsSoapHeader)
.then(result => {
// Iterate over the result and extract Id and ChangeKey of the messages and pass those to GetItem function to read messages
})
// For reading individual messages returned by FindItem (using Id and ChangeKey)
var ewsFunction = 'GetItem';
var ewsArgs = {
'ItemShape': {
'BaseShape': 'Default',
't:AdditionalProperties': {
't:FieldURI': {
'attributes': {
'FieldURI': 'item:Attachments'
}
}
}
},
'ItemIds' : {
'ItemId': {
'attributes': {
'Id': Id,
'ChangeKey' : ChangeKey
}
}
}
};
await ews.run(ewsFunction, ewsArgs, ewsSoapHeader)
.then(result => {
// Iterate over the result and extract meesage
})

Although I delete the data, I cannot see it being deleted unless I refresh the page

When I click it, it adds the data, but when I refresh the page, I can see that it was added.
Deleting like this is doing the same problem. I delete, but I can only see that when I refresh the page, it is deleted. How can I solve this situation?
app.component.ts
constructor(private srv: UserServiceService) {}
users: any = [];
checkForm: any;
name: FormControl;
surname: FormControl;
age: FormControl;
async ngOnInit() {
(this.name = new FormControl(
"",
Validators.compose([Validators.required])
)),
(this.surname = new FormControl(
"",
Validators.compose([Validators.required])
)),
(this.age = new FormControl(
null,
Validators.compose([Validators.required])
));
this.getAllUsers();
}
async getAllUsers() {
await this.srv.allUsers().subscribe(val => {
this.users = val;
});
}
addUserFunction() {
this.srv
.addUserService(this.name, this.surname, this.age)
.subscribe(val => {
console.log("val: ", val);
});
this.name.reset();
this.surname.reset();
this.age.reset();
}
async deleteUser(id) {
await this.srv.deleteUserService(id).subscribe(user => {
console.log(user);
});
}
user-service.service.ts
export class UserServiceService {
constructor(private http: HttpClient) {}
allUsers() {
return this.http.get("http://localhost:3000/get_users");
}
addUserService(name, surname, age) {
return this.http.post("http://localhost:3000/add_user", {
name: name,
surname: surname,
age: age
});
}
deleteUserService(id) {
return this.http.delete("http://localhost:3000/delete_user/" + id);
}
}
On successful delete you can filter your user if you don't want to go to the server to fetch a fresh list of users like this:
this.users = this.users.filter(function(index) {
return this.users.id== index;
});
So you can put this to your delete method in subscribe.
Also you can use the same approach on create, just put new user to the list, or fetch fresh ones from the server.
I would suggest that in your create method you return new user which is added to DB and put that object in your array on client side so you can have full object from server in one call.
Refresh the data by calling the getAllUsers() method in your component again after deleting/creating a user. Since ngOnInit() only gets called one time after your component is created.

I need to know how to add pagination with vue.js?

I Have html+javascript that requests from mongodb database some games(game1,2,3,4,5,6)just simple database with alot of games.
I want to know how via vue.js i can do pagination that per page show 4games.?
const SEARCH = new Vue({
el: '#search',
data: {
query: {
name: '',
max_price:0,
game_category:'',
game_publisher:'',
},
games: [] // current list of games. we re-fill this array after search
},
methods: {
btn_search: function () {
// now we know that this.query is our search critearia object
// so we can do fetch, and will do.
fetch('/search?json=' + JSON.stringify(this.query))
.then((response) => { //as you remember - res is a buffer.
return response.text();
})
.then((text_response) => {
console.log('got response!');
let games_from_server = JSON.parse(text_response);
this.games.splice(0, this.games.length); //it will remove all elemtns from array remove all elemtns from array
// and add games from server one by one.
for (let i = 0; i < games_from_server.length; i++) {
this.games.push(games_from_server[i]);
}
});
console.log(this.query);
}
}
});
console.log('pew?');
If you want to do a client-side pagination you can do it this way:
In your data add currentPage: 1 and gamesPerPage:
data() {
return {
currentPage: 1,
gamesPerPage: 4,
games: []
}
}
then add a computed property paginatedGames which is your games property split into pages, a currentPageGames property which filters games in current page and changePage method which changes your page:
computed: {
paginatedGames() {
let page = 1;
return [].concat.apply(
[],
this.games.map( (game, index) =>
index % this.gamesPerPage ?
[] :
{ page: page++, games: this.games.slice(index, index + this.gamesPerPage)}
)
);
},
currentPageGames() {
let currentPageGames = this.paginatedGames.find(pages => pages.page == this.currentPage);
return currentPageGames ? currentPageGames.games : [];
}
},
methods {
changePage(pageNumber) {
if(pageNumber !== this.currentPage)
this.currentPage = pageNumber;
}
}
Complete example: http://jsfiddle.net/eywraw8t/217989/
However, if your database has lots of games, it might be a better idea to implement a server-side pagination and fetch games only for requested page.

Resources