Phoenix Live View keeps rebuilding a DOM element with phx-update="ignore" - phoenix-live-view

In my contrived chat app, I have a timestamp at the bottom that is supposed to tell when the page loaded. Adding chats should not change it, and I included a phx-update="ignore" attribute on the div containing the timestamp to prevent that:
<div id="date" phx-hook="Date" phx-update="ignore"></div>
However, the timestamp does get updated when chats are added. Here is the initial state:
Then I click New Chat and the dialog appears:
I inspected the DOM and I know that step did not change the timestamp. However, when I press the Save button, the timestamp does change:
How can I prevent that from happening?

The Save button in the dialog was triggering a redirect that caused the page to refresh, so I fixed that by replacing the dialog with some widgets with phx-hook fields, sending the chats to the server with pushEvent in app.js:
index.html.leex
<input id="usernameinput" placeholder="Your name" phx-update="ignore"/>
<input id="chatinput" placeholder="Say something"/>
<button id="newchatbtn" phx-hook="ChatSend">Send</button>
app.js:
Hooks.ChatSend = {
mounted() {
let viewHook = this
this.el.addEventListener("click", function() {
let uni = document.getElementById("usernameinput")
let ci = document.getElementById("chatinput")
viewHook.pushEvent("send-chat", {msg: ci.value, username: uni.value})
})
}
}
index.ex:
#impl true
def handle_event("send-chat", %{"msg" => msg, "username" => username}, socket) do
{:ok, c} = Chats.create_chat(%{username: username, body: msg})
cs = socket.assigns.chats
cs = cs ++ [c]
socket = assign(socket, :chats, cs)
{:noreply, socket}
end
Here is the commit.

Related

Placeholder disappear after user interact with inputs

I'm facing this issue in my react app:
The application is used for manage storage of a shop, there is one page in which user can add a new obj ( with name , quantity etc.) and there is a page used for UPDATE the obj.
In the "update" page I display the same form of the "new" page but with the current value as placeholder, so that the user can see what value is actually set and change just one or few of the values and leave the others as they are.
The problem is that when the user interact with the input ( like start typing then cancel ) the placeholder disappear and the value is updated as empty.
Now I would like that if user leaves the field empty after interacting with it, the placeholder should appear again, and I would like to make that if the input is left empty then it would not be updated or should be updated with the previous value.
I'm using antd library, so all inputs and stuff are taken from there.
const [data, setData]=useState({
numero: 0,
date: '' ,
nome: "",
...
//get current data
useEffect(() =>get(child(dbRef,'test/' + searchParams.get('id'))).then((snapshot)=>{
if(snapshot.exists()){
setData(snapshot.val())
console.log('[CONVERTED-DATA]',snapshot.val(), '[stato]', data);
}else{
console.log('[GET] NO data available')
}
}).catch((error)=>{
console.log(error)
})
, [])
//now "data" is populated with the values from db
function onChange(e) {
const value = e.target.value ;
setData({
...data,
[e.target.name]: value
});
console.log("[CHANGE-VALUE]", value);
console.log("[event]", e);
}
<Form>
<Form.Item
name="nome"
label="Nome"
rules={[ { type: "string", min: 3 }]}
initialValue={data.nome}
>
<Input
placeholder={data.nome}
value={data.nome}
name="nome"
onChange={onChange}
className="update-input"
/>
</Form.Item>
... more inputs

Retrieve ID after pushing to SharePoint list using React PNPJs

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
};

react address lookup issue with changing final input value

I am building an address lookup functionality for an app, and my previous 2 questions have thus far, been unable to garner an answer. I am on the last step, and need to figure this out, so I turn to you stack overflow.
I start with an input, a button and a target input:
<input type='text' name='postcode-lookup' onChange={this.postcodeChange} />
<button onClick={this.searchPostcode}>Search</button>
<input type='text' name='target-for-data' />
Easy enough. Now for the functions attached to both of those elements:
postcodeChange = {e} => {
this.setState({'postcode': e.target.value});
}
searchPostcode = () => {
this.setState({'visible': true});
if(this.state.postcode.length . 0){
Axios.get('postcode look up api here')
.then(response => {
this.setState({'response': response.data});
})
}
}
Ok here, we have 3 state items: postcode, which we will set to an empty string '', visible, which is initially set to true, and response, which is an empty array, that we then populate with the response data of address objects.
My next step, was to display those addresses, so inside the render, I set a const that maps over the response array like so:
const result = this.state.response.map((item) => {
if(this.state.visible === true){
return(
<p key={item.id} onClick={addressClick}>{item.address1Field}</p>
)
}else {
}
})
Ok, so when we click the button, it will return a p tag filled with address data from the array. This also has a function, which is where my problem lies.
Inside of this function I set the visible state item to false, so that the addresses disappear. Easy enough.
But how do I then take the address that I clicked on, and populate it into the original input we started with?
I have tried many things, from setting the state in addressClick, targeting the innerHTML, e.target.value, e.target.innerHTML, and so on and so on for hours.
Any takers? Ideas?

How can I set customvalidity to have a Link in it?

I have a customvalidity function for when a username or email are taken, and I want to give the user the option to go to signin from there. Is this possible?
I have tried creating an object for the Link object, from react-router dom, but it eiter doesn't come up when added with a comma, or comes back object object when inserted with a plus sign. I want the email taken notification to have the link in it so the user can click on login directly.
handleSubmit = async (e) => {
e.preventDefault();
const EmailField = document.getElementById('email');
const userField = document.getElementById('username');
const signinRedirect = <Link to='/signin'> login </Link>;
const newUser = {
username : this.state.username,
email : this.state.email,
password : this.state.password,
confirmPassword : this.state.confirmPassword,
};
//check passwords match before submitting
if (this.state.passwordsMatch) {
let url = window.location.hostname.split('.')[0] === 'localhost' ? 'http://localhost:3306' : 'https://petsosbackend.apps.nonprod-mpn.ro11.allstate.com';
try {
await axios.post(url + '/register', newUser)
.then(res=> {
if (res.status===202) {
this.props.history.push('/registersuccess');
//if email is taken
} else if (res.data==='email'){
EmailField.setCustomValidity('Email address is in use, please select another or '+ {signinRedirect});
EmailField.reportValidity();
//if name is taken
} else if (res.data==='name') {
userField.setCustomValidity('Username is in use, please select another or' + signinRedirect);
userField.reportValidity();
}
})
} catch(error) {
console.log("Catch = ", error.response);
}
}
}
There is more logic obviously but think these are the two key parts and just need help figuring out how to have the signinRedirect appear in the validity warning.
Thanks a lot!
Principle:
return (
<div className="form-control">
<input type="text" name="email" value={email} onChange={handleChange} />
{isEmailInUse && (
<div className="error">
Email address is in use, please select another or <Link to='/signin'>Sign in</Link>
</div>
)}
</div>
);
You are trying to use native messages in a JSX validation method. So you can not do.
JSX has nothing to do with HTML, besides being a way of describing the structure of a document and a similar syntax.
JSX In Depth
Just do not use native error reporting. Use your own solutions, like the ones I gave in the answer.
You are also working incorrectly with DOM elements. In React, it is common practice to use Ref API or monitored components.
And whenever possible, there should be no conditions in the code like:
window.location.hostname.split('.')[0] === 'localhost'
For such tasks there are env variables and configurations. You can set BASE_URL and use different values for different modes.

Copy to the Clipboard in Lightning Component

I'm creating Lightning Component that displays Classic version of the Current URL record page with a button that onclick copy to the clipboard that URL.
Just a simple functionality that saves time for Lightning Users, when they need to send a URL of the record to non-Lightning users.
Cmp:
<lightning:button class="slds-align_right slds-button slds-button_neutral" iconName="utility:copy_to_clipboard" variant="border-filled" label="Copy" onclick="{! c.copyClassic }"/>
<textarea readonly="true" id="urlClassic">https://name.my.salesforce.com/{!v.recordId}</textarea>
Controller:
({
copyClassic : function(cmp, event){
var urlClassic = document.getElementById('urlClassic');
urlClassic.select();
document.queryCommandSupported('copy');
document.execCommand('copy');
var source = event.getSource();
source.set('v.label', 'COPIED!');
setTimeout(function(){
source.set('v.label', 'Copy');
}, 2000);
} })
It is working on first copied page, but if I open in the same window new record, Textarea displays new URL (with the new record page) and button changed to 'COPIED!' but it's not selecting and copying new URL.
Does anyone has similar issue or idea to solve this problem?

Resources