Retrieve ID after pushing to SharePoint list using React PNPJs - reactjs

I'm building a SharePoint SPFx react app. In a nutshell, the user fills out a form that I created. When the user hit's submit, using PNPJs: https://pnp.github.io/pnpjs/sp/items/ I'm adding the item to a list called Request.
From there I want to send an email that contains the URL link to that item they created. Right now, my code adds the item to the list and I'm able to send an email with no problem. However, I want to get the ID of the item that was just added to the list, so that I can add it to the email.
Here is a striped down snippet of my function that adds items to the Request list.
async submitNewRequest():Promise<any> {
let preprocessedData;
try {
// add an item to the list
pnp.sp.web.lists.getByTitle("Requests").items.add({
Title: this.state.Title,
Requestor_x0020_Email: this.state.getEmail,
Created: this.state.startDate,
}).then((iar) => {
console.log(iar);
//Is this where I would get the ID
});
const emailProps: EmailProperties = {
To: [this.state.getEmail],
Subject: "Your court requisition has been submitted.",
Body: this.initalMessage
};
} catch(error) {
}
return preprocessedData;
}
I believe what I have to do is in the .then((iar) => { when item is successfully added to the list, to get a response back with that item ID. But I'm not sure how. In my const emailProps: EmailProperties is where I'm sending the email, which again works.
Typically I can do something like this await sp.web.lists.getByTitle("Request").items.getById(1).get(); and in the console I will get back something like this:
0:
Title: "My title here"
Description: "Description Here"
ID: 24
Here is on submit function:
async _onNewRequest(event) {
event.preventDefault();
await this.submitNewRequest();
this.displayPop();
}
And lastly my email function:
get initalMessage() {
return `<p>This is my email template that I stripped down.</p>
<p>
<a href="https://mywebsite.sharepoint.com/sites/Requests/SitePages/Home.aspx#/MyRequests/'+ NEED_ID_HERE +'" target="_blank">
Click Here
</a>
</p>`;

You could retrieve the Id of the item like this:
sp.web.lists.getByTitle("ct0").items.add({
Title:"test"
}).then(iar=>{
console.log(iar.data.ID);
})
The code would be like this:
const iar=await sp.web.lists.getByTitle("ct0").items.add({
Title:"test"
});
const id=iar.data.ID;
const emailProps: EmailProperties = {
To: [this.state.getEmail],
Subject: "Your court requisition has been submitted.",
Body: this.initalMessage,
ID:id
};

Related

How can I create a parent html element by appending sub element from an object?

In my react app I need to return a line which will be created based on a list.
Here is the object,
searchCriteria: {
op_company: "039",
doc_type: "ALL"
}
and in my UI, i need to show it as a paragraph with bold values. So the hard coded code would be like below
<p>Download request for op_company: <b>{searchCriteria.op_company}</b>, doc_type: <b>{searchCriteria.doc_type}</b></p>
But the object(searchCriteria) will be changed based on the user request. So I tried like below.
const getSearchCriteria = (criteria) => {
let searchCriteria = []
searchCriteria.push('Download request for')
Object.keys(criteria).forEach((key) => {
if(criteria[key] !== '') {
searchCriteria.push(` ${key}: ${criteria[key]},`)
}
});
return searchCriteria;
}
return (
<p>
{getSearchCriteria(searchCriteria).map((item) => <span key = {item}>{item}</span>)}
</p>
);
here i'm getting the expected output. But I can't get the value as bold (highlighted). Is there another way to directly deal with html elements?

Adding data to DB using an Axios request yields Internal Server Error

I'm creating a form using Vue JS (more specifically the Vuetify library) and when clicking the 'Add' button I am trying to make it so that the user input is added to the database.
The database has 3 columns: id, type_id, value. I want to link the user input to the value column.
Note that allDesserts is an array that stores all of the items in the database. This is what I want to add to.
How can I achieve this?
Component in my form:
<v-combobox
:items="allDesserts.map(a => a.value)"
label="Project Type"
:search-input.sync="search"
>
<template v-slot:no-data>
<v-text-field
label="Add new dessert"
v-model="search"
>
</v-text-field>
<v-btn
#click="enterKey"
>Add</v-btn>
</template>
</v-combobox>
Axios request/method:
enterKey () {
axios.post('/api/desserts', {
value: 'key'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error.response);
});
}
My controller:
public function storeDessert(Request $request)
{
$dropdownType = new DropdownType();
$dropdownType->attribute_id = $request->input(rand(1, 10000));
$dropdownType->value = $request->input('value');
$dropdownType->save();
}
I am getting the following error:
"Illegal string offset 'id'"
I think your error is on this line.
$dropdownType->attribute_id = $request->input(rand(1, 10000));
Let say rand(1, 10000) will give you a value of 100, now you used this 100, as a key to access value in your requests which is not available.
Try to look your payload. You are just passing a data which has a key value only, this one.
{value: 'key'}
and now this line will work cause it is available in your payload.
$dropdownType->value = $request->input('value');
But not this one.
$dropdownType->attribute_id = $request->input(rand(1, 10000));

How to add onclick functionality in lightning web component data table URL column

I have created a lightning-datatable in LWC and added a custom column that displays a URL. Now, I would like to add onclick event in the URL field and want to pass row information to the javascript method.
The idea is to render the component markup that will display all the information about the item that was clicked (within the same LWC).
Can anyone please help me on this; how I can add an onclick event in URL and handle the click event with a function in LWC datatable?
test.html
<div class="" style="height:420px">
<lightning-datatable key-field="Id"
data={lstAllRows}
columns={columns}
onrowaction={handleRowAction}
enable-infinite-loading
load-more-offset={intLoadOffset}
onloadmore={handleLoadMoreData}
hide-checkbox-column>
</lightning-datatable>
</div>
test.js
getRequiredList(){
getTabelData({
strName: this.strName
}).then(response =>{
this.lstTmp = response.lstExistingData;
this.lstTmp.forEach(function(record){
record.linkName = '/lightning/r/'+record.Id+'/view';
});
this.lstAllRows = this.lstTmp;
}).catch(error =>{
this.strRecordErrorMessage = error.body.message;
console.log('Error in getting the accounts', this.strRecordErrorMessage);
})
}
this.columns = [
{ label: this.label.columnName, fieldName: 'linkName', type: 'url',
typeAttributes: {label: { fieldName: 'Name' }, target: '' },
cellAttributes: { }
}]
Where I am adding url:
record.linkName = '/lightning/r/'+record.Id+'/view';
I would like to add an onclick event here and stop the URL redirect behaviour. Any click on the URL should not redirect user to the new page; instead of that, a piece of markup should render the record details on the same LWC.
You can probably achieve what you need by two means :
Create a Static Row-Level Action
Create a Custom Data Type
For more information you can go there: https://developer.salesforce.com/docs/component-library/bundle/lightning-datatable/documentation
P.S: here are some basic javascript improvements
async getRequiredList () {
try {
const response = await getTabelData({
strName: this.strName
});
this.lstAllRows = response.lstExistingData.map(record => ({
...record,
linkName: `/lightning/r/${record.Id}/view`,
}));
} catch (error) {
this.strRecordErrorMessage = error.body.message;
console.log('Error in getting the accounts', this.strRecordErrorMessage);
})
}
I suppose the record is an object and not an HTML element.
What you could probably do is:
const records = querySelectorAll('.record') // add a class to your records
records.forEach(record => {
record.addEventListener('click', function(e){
e.preventDefault(); // you don't want the default behavior
// your code goes here
console.log({ e })
});
});

Dropdown list not showing default item

I am using the semantic-ui-react dropdown list, which I have working just fine. The problem is, on my form I am pulling data from a database using the Mobx store. I have a array setup for the options in the dropdown list. when the form loads from the store the text field for the dropdown list is blank, if I click on the dropdown I can see that the selected option is highlight (bold). How do I get the text field to show the default options. I have included some code below if anyone can look at it and give me an idea of what I need to do.
Thanks for all your help.
Here is the code for the dropdown list:
<div className="col-sm-3">
<div className="bg-primary text-white text-center">
Driver
</div>
<div>
<Dropdown
selection
fluid
id="driver"
name="driver"
ref="driver"
onChange={this.handleChange}
value={this.props.EquipmentStore.truck_detail.driver}
options={this.props.EquipmentStore.driver_list}/>
</div>
</div>
Here is how I am building the driver_list, I am basically getting a list of users from the database and create an array with value and text fields
let newUserItem = {
value: getUser.id,
text: getUser.first_name + " " + getUser.last_name
};
this.driver_list.push(newUserItem)
The value in the truck_detail.driver is a numberic value that the same value in the value field in the driver_list value field...that is all working fine, I can not get the text value to show in the text field for the dropdown list by default.
Here is the code that I use to build the options list:
async loadDriverList() {
let endpoint = '/api/users/profile/?owner=True';
this.driver_list.length = 0;
let lookupOptions = {
method: "GET",
headers: {
'Content-Type': 'application/json'
}
};
try {
const response = await fetch(endpoint, lookupOptions);
const profile_list = await response.json();
const userItem = {value:0, text:'Select Driver'};
this.driver_list.push(userItem);
let array_length = profile_list.length;
for (let i = 0; i < array_length; i++) {
let ownerId = profile_list[i].user;
let endpoint = '/api/users/users/' + ownerId + '/';
let userList = await fetch(endpoint, lookupOptions);
let getUser = await userList.json();
let newUserItem = {
value: getUser.id,
text: getUser.first_name + " " + getUser.last_name
};
this.driver_list.push(newUserItem)
}
} catch(e) {
console.log(e)
}
}
After a lot of conversation with Predrag Beocanin I have solved this issue. What it boils down to is my form (with the Dropdown) was getting render before the options list was fully populated. In my application I have a form that shows a list of items, once you click on the item it will render a detailed form of that listed item. Originally I wall trying to populate my options list once you click on the item you wanted to view the details on. Because the options list is basically a static list, I am now populating that list when you are view the first form. Now when you click on the item to view the Dropdown options are fully populated and working just as I had expected.
Thanks for your help Predrag.

React, dynamically add text to ref span

I'm trying to render a message to a span tag specific to an item in a list. I've read a lot about React 'refs', but can't figure out how to populate the span with the message after it's been referenced.
So there's a list of items and each item row has their own button which triggers an API with the id associated with that item. Depending on the API response, i want to update the span tag with the response message, but only for that item
When the list is created the items are looped thru and each item includes this
<span ref={'msg' + data.id}></span><Button onClick={() => this.handleResend(data.id)}>Resend Email</Button>
After the API call, I want to reference the specific span and render the correct message inside of it. But I can't figure out how to render to the span at this point of the code. I know this doesn't work, but it's essentially what I am trying to do. Any ideas?
if (response.status === 200) {
this.refs['msg' + id] = "Email sent";
I recommand using state. because string refs legacy (https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs)
const msgs = [
{ id:1, send:false },
{ id:2, send:false },
{ id:3, send:false },
];
this.state = {
msgs
};
return this.state.msgs.map((msg, index) => {
const status = msg.send ? "Email Sent" : "";
<span>{ status }</span><Button onClick={() => this.handleResend(index)}>Resend Email</Button>
});
async handleResend (index) {
const response = await callAPI(...);
if(reponse.status !== 200) return;
const newMsgs = _.cloneDeep(this.state.msgs);
newMsgs[index].send = true;
this.setState({
msgs: newMsgs
})
}
The workaround is set innerText
this.refs['msg' + id].innerText = "Email sent";
But rather than using ref try to use state to update elements inside render.
i was facing with this issue right now and i figured it out this way:
// currentQuestion is a dynamic Object that comes from somewhere and type is a value
const _target = `${currentQuestion.type}_01`
const _val = this[`${_target}`].current.clientHeight // here is the magic
please note that we don't use . after this to call the ref and not using refs to achieve what we want.
i just guessed that this should be an Object that would hold inner variables of the current object. then since ref is inside of that object then we should be able to call it using dynamic values like above...
i can say that it worked automagically!

Resources