Socket.Io event hitting multiple times - javascript

index.js
const messageContainer = document.querySelector('.msg');
const append = (message, position) => {
console.log(message)
const messageElement = document.createElement('div');
messageElement.innerText = message;
messageElement.classList.add('message');
messageElement.classList.add(position);
console.log(messageElement)
messageContainer.append(messageElement);
console.log(messageContainer)
};
const SERVER = "http://localhost:3010";
var socket = io(SERVER);
socket.on('receive_message', (message) => {
console.log('Connected');
console.log(message.content);
setRMsg(message);
console.log(rmsg)
// append(`${message ? message.name : ''}: ${message ? message.content : ''}`, 'right');
// // if (message.sendBy === 'user') {
// append(`${message.content} `, 'left');
// };
});
console.log(rmsg);
if (rmsg && rmsg != '') {
append(`${rmsg.content} `, 'left');
setRMsg('')
}
const send = () => {
console.log('*95')
console.log(sending)
if (sending === '' || sending.senderChatID === '' || sending.content === '' || id === '') {
console.log('***')
toast.error('Missing Required Field', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
}
else {
let obj = {
senderChatID: sending.senderChatID,
receiverChatID: id,
content: sending.content,
sendBy: sendVia,
chatId: id,
name: name ? name.name : '',
profile_pic: name ? name.profile_pic : '',
role: name ? name.role : '',
createdAt: new Date(Date.now()),
user_id: id
};
append(`${name ? name.name : ''}: ${sending.content}`, 'right');
const input = document.getElementById('messageInp');
input.value = '';
socket.emit('send_message', obj);
}
'recieve_message' event is hitting multiple times but it must hit single time whereas on click of button send function works fine but while recieving message it gets hit multiple time don't know why as i am new to socket.io may be I was doing small mistake. Any help will be appreciated

You're probably re-registering the socket.on(...) at each re-render of your React component. Get that code inside a useEffect with [] array to do that just one time like so :-
const socketObj = useRef(io("http://localhost:3010"));
const socket = socketObj.current;
useEffect(()=>{
socket.on('receive_message', (message) => {
console.log('Connected');
console.log(message.content);
setRMsg(message);
console.log(rmsg)
// append(`${message ? message.name : ''}: ${message ? message.content : ''}`, 'right');
// // if (message.sendBy === 'user') {
// append(`${message.content} `, 'left');
// };
});
},[]);
Here I have used socket as a ref since I believe it won't change once initialized and participate in the render flow but you can even make it as a state as well if you need.

Related

How to I dispatch a state value to an const variable in Redux-toolkit?

I am trying get an error to show in my component which is being dispatched from my actions and assigned to my errorAlert constent, however it always comes back as null even when there is content in my state as per console.log. I have shared the console log results below.
Is there an issue when assigning a redux state variable to a const?
slice.js
const auth = createSlice({
name: "auth",
initialState: verifiedResult: {},
reducers: {
verifySuccess(state, { payload }) {
state.verifiedResult = payload;
state.isLoading = false;
state.error = null;
}
}
action.js
...
if (result.state === "pending") {
await new Promise((resolve) => setTimeout(resolve, 10000));
} else if (result.state === "failed") {
dispatch(verifySuccess(result));
break;
component.js
....
const errorAlert =
auth.verifiedResult.cel_number === false
? "The number associated with your account is not a valid."
: auth.verifiedResult.prepaid_number === false
? "Mobile number is not Prepaid or is not active."
: auth.verifiedResult.has_recharged === false
? "Mobile number must be recharged in the past 30 days"
: null;
return (
<>
{errorAlert && <div>{errorAlert}</div>}
</>
)}
console.log
::auth.verifiedResult::
{
state: "failed"
cel_number: 'XXX XXX XXX'
prepaid_number: false
recharged: false
}
:::errorAlert::: null
It shows Mobile number is not Prepaid or is not active. in my case. Make sure your auth.verifiedResult is correctly written(you don't use comma after every object property).
const auth = {};
auth.verifiedResult = {
state: 'failed',
cel_number: 'XXX XXX XXX',
prepaid_number: false,
recharged: false,
};
const errorAlert =
auth.verifiedResult.cel_number === false
? 'The number associated with your account is not a valid.'
: auth.verifiedResult.prepaid_number === false
? 'Mobile number is not Prepaid or is not active.'
: auth.verifiedResult.has_recharged === false
? 'Mobile number must be recharged in the past 30 days'
: null;
console.log(errorAlert); // Mobile number is not Prepaid or is not active.
Did you mean
if (result.state === "pending")?

Angular: how to wait for the request response and after that proceed next step in function

I have a little problem with my function, one of the params that I want to set I'm getting from the http request. The problem is that the final data from method below is recalculated in one of the components, and when it happens the result of request is still null. When the response come it's not triggering onChanges so I can't recalculate this data again, and doCheck triggering "too often".
updateData(componentRecords: ComponentRecord[], importSourceGroup?: ImportSource[], isImportSource = false, component: DiaryNode = null) {
const recordData = [];
const records = isImportSource ? importSourceGroup : componentRecords;
for (const record of records) {
const recordRow: any = record.ID === 'addingRow' ? record : {
ID: record.ID,
InputTypeID: record.InputTypeID,
SubRecords: record.SubRecords,
attachmentField: record.Fields ? record.Fields.find(({Type}) => Type === DiaryFieldType.ATTACHMENT) : null,
documentsFolder: null,
DateUpdated: null,
ComponentInstanceID: null,
linkedUnits: {},
recordRef: record
};
if (record.ID !== 'addingRow') {
if (isImportSource) {
recordRow.DateUpdated = (record as ImportSource).DateUpdated;
recordRow.ComponentInstanceID = (record as ImportSource).ComponentInstanceID;
}
if (recordRow.attachmentField && recordRow.attachmentField.Value) {
this.subManager.add(this.documentsApiService
.getFileDetailsByFolderID(recordRow.attachmentField.Value)
.subscribe((documents: DocumentsFolder) =>
recordRow.documentsFolder = documents));
}
if (record.Fields) {
for (const field of record.Fields) {
const label = field.Label;
recordRow[label] = field.Type === DiaryFieldType.INTEGER ? parseInt(field.Value, 10) : field.Value;
const schema = component && component.Schema && component.Schema.find(diaryFormField => diaryFormField.Label === label);
if (schema && schema.LinkedUnit) {
recordRow.linkedUnits[label] = schema.LinkedUnit.Attributes.List.PickListItems[0].Label;
}
}
}
}
recordData.push(recordRow);
}
return recordData;
}
The part that is async is
if (recordRow.attachmentField && recordRow.attachmentField.Value) {
this.subManager.add(this.documentsApiService
.getFileDetailsByFolderID(recordRow.attachmentField.Value)
.subscribe((documents: DocumentsFolder) =>
recordRow.documentsFolder = documents));
}
So I don't know what is the best solution for this but I was wondering if it's possible to wait here for the response, and go furthure when it comes.
What do you think?
In short the property cannot be assigned synchronously using the asynchronous HTTP request. Instead you need to make entire paradigm asynchronous. Then you could subscribe to the function updateData() to fetch the array.
Additionally you could use RxJS forkJoin function to combine multiple parallel observables. Try the following
updateData(
componentRecords: ComponentRecord[],
importSourceGroup?: ImportSource[],
isImportSource = false,
component: DiaryNode = null
): Observable<any> { // <-- return `Observable` here
const records = isImportSource ? importSourceGroup : componentRecords;
return forkJoin( // <-- use `forkJoin` to combine multiple parallel observables
records.map(record => {
const recordRow: any = record.ID === 'addingRow' ? record : {
ID: record.ID,
InputTypeID: record.InputTypeID,
SubRecords: record.SubRecords,
attachmentField: record.Fields ? record.Fields.find(({Type}) => Type === DiaryFieldType.ATTACHMENT) : null,
documentsFolder: null,
DateUpdated: null,
ComponentInstanceID: null,
linkedUnits: {},
recordRef: record
};
if (record.ID !== 'addingRow') {
if (isImportSource) {
recordRow.DateUpdated = (record as ImportSource).DateUpdated;
recordRow.ComponentInstanceID = (record as ImportSource).ComponentInstanceID;
}
if (record.Fields) {
for (const field of record.Fields) {
const label = field.Label;
recordRow[label] = field.Type === DiaryFieldType.INTEGER ? parseInt(field.Value, 10) : field.Value;
const schema = component && component.Schema && component.Schema.find(diaryFormField => diaryFormField.Label === label);
if (schema && schema.LinkedUnit) {
recordRow.linkedUnits[label] = schema.LinkedUnit.Attributes.List.PickListItems[0].Label;
}
}
}
if (recordRow.attachmentField && recordRow.attachmentField.Value) {
return this.documentsApiService.getFileDetailsByFolderID(recordRow.attachmentField.Value).pipe( // <-- return the HTTP request
map((documents: DocumentsFolder) => ({ ...recordRow, recordRow.documentsFolder: documents })) // <-- spread operator to append new value to object
);
}
return of(recordRow); // <-- use `of()` to return as observable
}
return of(recordRow); // <-- use `of()` to return as observable
})
);
}
See here to learn more about fetching info from async request.

how can i add reply message in conversejs

I am using converse.js to provide chat functionality. I am looking for a way to add reply to specific chat room message. any one know how can i do that?
for example:
in group user1 send: hello
and user2 wants reply to this message and say hello to
my initial code:
<script>
converse.initialize({
authentication: 'login',
//
auto_login: true,
allow_logout: false,
show_client_info: false,
allow_adhoc_commands: false,
allow_contact_requests: false,
hidden_occupants: true,
blacklisted_plugins: [
'converse-register',
'converse-rosterview',
'converse-bookmarks',
'converse-profile',
],
jid: "person#example.com",
password: "somepassword",
auto_join_rooms: [
{
'jid': 'group#conference.example.com',
'nick': 'myname',
'name': 'title',
'minimized': true
},
],
//
auto_reconnect: true,
bosh_service_url: 'https://example.com:7443/http-bind/',
message_archiving: 'always',
view_mode: 'fullscreen'
});
</script>
thanks all.
Finally I find way to solve this problem.
first in convers.js/src/plugins/chatview/view.js add this before onMessageEditButtonClicked:
onMessageReplyButtonClicked (message) {
const currently_correcting = this.model.messages.findWhere('correcting');
const unsent_text = this.el.querySelector('.chat-textarea')?.value;
if (unsent_text && (!currently_correcting || currently_correcting.get('message') !== unsent_text)) {
if (!confirm(__('You have an unsent message which will be lost if you continue. Are you sure?'))) {
return;
}
}
this.insertIntoTextArea(u.prefixMentions(message, true), true, false);
},
and in convers.js/src/components/message-actions.js file add below code before onMessageEditButtonClicked
onMessageReplyButtonClicked(ev) {
ev.preventDefault();
this.chatview.onMessageReplyButtonClicked(this.model);
}
and in convers.js/src/headless/utils/cores.js change the u.prefixMentions function to:
u.prefixMentions = function (message, reply = false) {
/* Given a message object, return its text with # chars
* inserted before the mentioned nicknames.
*/
let text = message.get('message');
(message.get('references') || [])
.sort((a, b) => b.begin - a.begin)
.forEach(ref => {
text = `${text.slice(0, ref.begin)}#${text.slice(ref.begin)}`
});
if (reply){
const lines = text.split('\n');
let newtxt = ""
for(let i = 0;i < lines.length;i++){
if(!lines[i].startsWith(">")){
newtxt += "> " + lines[i] + "\n"
}
}
return "> reply to " + message.get('nick') + ":\n" + newtxt
}
else
return text;
};

Having problem in accessing values from state when traversing an array

i'm trying to traverse an Array and perform some operation. But cann't access the values as i want to.
inputObj.map(el => {
const msg = this.state.validation[el.id].message;
const msg2 = this.state.validation['name'].message;
})
Here, el.id can be name, dob or address. When i use this.state.validation[el.id].message;, it shows TypeError: Cannot read property 'message' of undefined. But if i hardcode it like this.state.validation['name'].message;, it works fine. when comparing both el.id and 'name', they have same datatype and same value. So, why having problem when using el.id instead of hardcoding it.
NB: i'm using reactjs.
Edit:
this.state:
this.state = {
super(props);
this.validator = new FormValidator([
{
field: 'name',
method: 'isEmpty',
validWhen: false,
message: 'Name is required'
},
...
]);
orderForm: {
name: {
elementType: 'input',
elementConfig: ''
},
...
}
validation: this.validator.setValid() // it will be the updated upon submitting form on submitHandler by calling validate() from FormValidator
}
inputObj:
const inputObj= [];
for(let key in this.state.orderForm){
inputObj.push({
id : key,
config: this.state.orderForm[key]
});
}
FormValidator
import validator from 'validator';
class FormValidator {
constructor(rules){
this.rules = rules;
}
setValid(){
const validation = {};
this.rules.map(rule => (
validation[rule.field] = {isValid: true, message: ''}
));
return {isValid: true, ...validation};
}
validate(form){
let validation = this.setValid();
this.rules.forEach( rule => {
if (validation[rule.field].isValid){
const field = form[rule.field].toString();
const args = rule.args || [];
const validationMethod = typeof rule.method === 'string' ?
validator[rule.method] : rule.method;
if (validationMethod(field, ...args, form) !== rule.validWhen){
validation[rule.field] = {isValid: false, message: rule.message};
validation.isValid = false;
}
}
});
return validation;
}
}
export default FormValidator;
You can check if this.state.validation[el.id] is defined before getting message key.
Like that you can't get fatal error.
inputObj.map(el => {
this.state.validation[el.id] && (
const msg = this.state.validation[el.id].message
);
})

Boolean State Value Changes to Undefined on Second onSubmit

I'm working on a React project and implementing email validation and setting the state to true when it doesn't pass and false when it does. Validation part works, but getting undefined state on second onSubmit.
A bit more detail: I'm checking the state onChange and onSubmit. onChange seems to work as expected. onSubmit does work on the first click/submit but the very next click/submit, it changes the state to 'undefined' and I have no idea why.
Best to view my codepen and start filling in the email field and checking the console as I'm logging the state.
Here's a snippet of the code:
this.state = {
inputs: {
name: '',
email: '',
message: '',
},
show: true,
errors: {
name: false,
email: false,
message: false,
},
};
validateEmail(email) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
handleOnChange = e => {
const { name, value } = e.target;
const emailInput = e.target.value;
const emailValid = this.validateEmail(emailInput);
if (name === 'email') {
this.setState({
inputs: {
email: emailInput,
},
errors: {
email: !emailValid,
},
});
} else {
this.setState({
inputs: {
...this.state.inputs,
[name]: value,
},
errors: {
...this.state.errors,
[name]: false,
},
});
}
console.log('errors.email onChange = ' + this.state.errors.email);
};
So, why is this happening? and how can I solve?
You have missed the else condition when the field is not empty. that will remove the error object key from state, that is the one gives you the undefined error.
rewrite the handleSubmit function like this.
handleSubmit = (e, slackPost) => {
e.preventDefault();
console.log('errors.email onClick = ' + this.state.errors.email);
let inputFields = document.getElementsByClassName('form-input');
let invalidEmailMessage = document.querySelector('#invalid-email-message');
let failMessage = document.querySelector('#fail-message');
let failMessageBox = document.querySelector('.alert-fail');
// empty array to house empty field names
const emptyFieldNames = [];
// empty object to house input state
let errors = {};
// loop through input fields...
for (var i = 0; i < inputFields.length; i++) {
if (inputFields[i].value === '') {
let inputName = inputFields[i].name;
// add name to new array
emptyFieldNames.push(inputFields[i].getAttribute('name'));
// add input name and value of true to new object
errors[inputName] = true;
failMessageBox.style.display = 'block';
} else {
let inputName = inputFields[i].name;
errors[inputName] = false;
}
}
debugger;
this.setState({ errors });
if (emptyFieldNames.length > 0) {
failMessage.innerHTML =
'Please complete the following field(s): ' + emptyFieldNames.join(', ');
} else if (this.state.errors.email === true) {
invalidEmailMessage.innerHTML = 'Please enter a valid email';
} else {
console.log('For Submitted!');
}
};

Categories