user111111 user111111 - 1 month ago 22
MySQL Question

How to delete message in all users using socket.io?

I am using socket.io and mysql (node server)

But I am not successful in delete function.

Here's what I have and what I've tried so far

io.on('connection', (socket) => {
connection.query("SELECT * FROM `messages`", (err, data) => {
for(let x in data) socket.emit('message', { id: data[x].message_id, text: data[x].message })
})
socket.on('disconnect', () => {
// console.log('user disconnected');
})

socket.on('add-message', (message) => {
addMessage(message, (res) => {
if(res) io.emit('message', { type: 'new-message', text: message});
})
});

socket.on('delete-message', (id) => {
connection.query("DELETE FROM `messages` WHERE `message_id` = '"+ id +"'");
io.emit('message', { type: 'delete-message', id: id }) // broadcast that something has changed
})
})


Angular2 service

import { Subject } from 'rxjs/Subject'
import { Observable } from 'rxjs/Observable'
import * as io from 'socket.io-client'

export class ChatService {
private url = 'http://localhost:5000'
private socket;

sendMessage(message) {
this.socket.emit('add-message', message);
}

getMessages() {
let observable = new Observable(observer => {
this.socket = io(this.url);
this.socket.on('message', (data) => {
observer.next(data);
});

return () => {
this.socket.disconnect();
};
})

return observable;
}

deleteMessage(id) {
this.socket.emit('delete-message', id);
}
}


Component

export class AppComponent implements OnInit, OnDestroy {
messages = []
connection;
message: any;

constructor(private chatService: ChatService){ }

sendMessage(): void {
this.chatService.sendMessage(this.message);
this.message = '';
}

ngOnInit() {
this.connection = this.chatService.getMessages().subscribe(message => {
this.messages.push(message);
})
}

ngOnDestroy() {
this.connection.unsubscribe();
}

deleteData(id): void {
for(var i = 0; i < this.messages.length; i++) {
if(this.messages[i].id == id) {
this.messages.splice(i, 1)
this.chatService.deleteMessage(id)

break;
}
}
}
}


Problem of what I have tried:

For deleteData(),
The user who clicked the delete button will have the desired view. But for other users, they must refresh for updated data.

Any help would be appreciated. Thanks.

Answer

First, keep in mind that you need to store all of your data into the array messages.

The challenging part is the message_id. Since you can't put a value on it. Assuming that it has an auto_increment. We need to add another table column which will have a unique value.

For my example, I will use message_identifier

The table will have (message_id, message_content, message_identifier)

To keep this short. message_identifier will just have time that converted to milliseconds(I believe). You must create a method that will make it completely different.

On your SERVER

Getting previous messages

connection.query("SELECT * FROM `messages`", (err, data) => {
    for(let x in data) socket.emit('message', { type: 'get-messages', message: data[x].message, identifier: data[x].identifier })
}

Adding message

socket.on('add-message', function(message, identifier) {
    connection.query("INSERT INTO `messages` (`message_content`, `message_identifier`) VALUES ('"+ message +"', '"+ identifier +"')", (err) => {
        if(!err) io.emit('message', { type: 'new-message', message: message, identifier: identifier })
    })
})

Deleting message

socket.on('delete-message', function(identifier) {
    connection.query("DELETE FROM `messages` WHERE `message_identifier` = '"+ identifier +"'", (err) => {
        if(!err) io.emit('message', { type: 'delete-message', identifier: identifier })
    });
})

The logic will be on the component. You just need to listen for 'message' and identify through the type that request is passing.

So, here it goes:

Importing socket.io and observable and declaring socket on your component.

import * as io from 'socket.io-client'
import { Observable } from 'rxjs/Observable'

private socket = io(/* url of server */); // inside AppComponent

On your class AppComponent. You need to listen to 'message'

let data$ = new Observable(observer => {
    this.socket.on('message', (data) => {
        if(data.type == 'get-message' || data.type == 'new-message') {
            observer.next({ message: data.message, identifier: data.identifier })
        } else if(data.type == 'delete-message') {
            for(let i = 0; i < this.messages.length; i++){
                if(parseInt(this.messages[i].identifier) == data.identifier){
                    this.messages.splice(i, 1);
                    break;
                }
            }
        }

        console.log(data)
    })
})

data$.subscribe(value => {
    this.messages.push(value);
})

You can put this on ngOnInit or constructor. I believe it should work either of this two.

On your SERVICE

Just remove getMessages since we're handling it on component.

Hope it helps. Cheers!