Please be advised that the message is currently in the process of being typed

In my current setup, I am utilizing Laravel 5.6.7, Socket.IO, and vue.js while excluding Pusher and Redis. The following is the code snippet I am using to send messages directly to a user engaged in one-on-one chatting with me.

var url = "http://localhost:6001/apps/My_appId/events?auth_key=My_Key";

var socketId = Echo.socketId();
var request = {
    "channel": "private-Send-Message-Channel.2",
    "name": "MessengerEvent",
    "data": {
        "msg": message
    },
    "socket_id": socketId
};
axios.post(url, JSON.stringify(request)).then((response) => {
    //Message Sent
});

I am exploring ways to notify the user I'm chatting with that I am currently typing a message. Is it necessary to use the same code above, which triggers an XMLHttpRequest for each keystroke? Is this the only method available to convey to the user that typing is ongoing?

Update 1

Is there a more efficient approach instead of posting an XMLHttpRequest for every key press as mentioned earlier? In case the user types 200 characters, does that mean I'll have to trigger an XMLHttpRequest 200 times?

Alternatively,

Does Laravel offer events like whisper and listenForWhisper, similar to what's detailed here https://laravel.com/docs/5.6/broadcasting#client-events? My tech stack involves vue.js and laravel 5.6.7, and I'm not utilizing Pusher nor Redis.

Answer №1

When you check out the broadcasting documentation, you will find two code snippets that are useful for your Vue.js application.

To send client events, you can utilize Echo's whisper method:

Echo.private('chat')
    .whisper('typing', {
        name: this.user.name
    });

To receive client events, you can use the listenForWhisper method:

Echo.private('chat')
    .listenForWhisper('typing', (e) => {
        console.log(e.name);
    });

If you want to debounce the whisper method while the user is typing, you can refer to lodash documentation.

If you prefer not to rely on an additional library like lodash, you can implement debounce by wrapping whisper in a timeout. The following snippet will broadcast the whisper every 300ms:

isTyping() {
    let channel = Echo.private('chat');

    setTimeout(function() {
        channel.whisper('typing', {
            name: this.user.name,
            typing: true
        });
    }, 300);
}

The isTyping() function should be triggered when an onkeydown event occurs in the chat application's input field.

You also need to listen for the whisper once the app is created. This method will set the typing variable to true for 600ms after receiving the event.

created() {
    let _this = this;

    Echo.private('chat')
        .listenForWhisper('typing', (e) => {
            this.user = e.name;
            this.typing = e.typing;

            // remove is typing indicator after 0.6s
            setTimeout(function() {
                _this.typing = false
            }, 600);
        });
},

Answer №2

Although I am not an expert in Laravel, I have encountered this issue before.

Let's start by defining what "typing" means. Simply put, a user is considered to be typing if the input field for sending a message is not empty.

This definition is not foolproof as the user may walk away from the keyboard while in the middle of typing a message and never return to finish or send it. Nevertheless, it serves its purpose adequately.

Now, we no longer need to monitor each keystroke to determine if the user is actively typing. Essentially, determining if a user is typing now boils down to chat_input_box.length > 0 in code representation.

The focus should be on syncing this boolean value across users and servers instead of tracking individual key presses. To ensure real-time updates, we must capture input events on chat_input_box. If the boolean value changes during an event, socket.io can then transmit a signal indicating whether the user has initiated or ceased typing.

Upon receiving this signal, appropriate views can be toggled to provide visual cues to the user regarding the app's current state.

To address the scenario where a user begins typing but abruptly leaves, a timeout mechanism can be implemented. Once the timer expires, the "is typing" boolean value resets to false. However, each subsequent typing activity restarts the timer automatically.

Answer №3

Instead of sending an xhr request to your app, you have the option to directly broadcast events to chat users without involving your app.

The Laravel documentation explains:

There are times when you may want to send out an event to other connected clients without interacting with your Laravel application. This can be handy for things like notifying users of "typing" activity, where you need to inform users that someone is typing a message on a specific screen. To broadcast client events, utilize Echo's whisper method:

Echo.private('chat')
    .whisper('typing', {
        name: this.user.name
    });

To listen for client events, make use of the listenForWhisper method:

Echo.private('chat')
    .listenForWhisper('typing', (e) => {
        console.log(e.name);
    });

Answer №4

Correct, it is more efficient to use debouncing instead of emitting on every character change. By using the debounce method from the lodash library, you can wait for a short period before triggering the function.

I suggest checking out the documentation at: https://lodash.com/docs/4.17.5#debounce

Laravel's Echo is also a good option, especially if you don't need server involvement for the typing action. Emitting directly from client to client can be more efficient in this scenario.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The variable _spPageContextInfo has not been defined, resulting in a ReferenceError

The code in my JavaScript file looks like this: var configNews = { url:_spPageContextInfo.webAbsoluteUrl, newsLibrary: 'DEMONews', listId: '' }; // Attempting to retrieve the List ID $.ajax({ url: configNews.url + "/_a ...

Finding elements based on their position using Javascript

I'm searching for an optimal method to identify all elements located within a specific range of pixels from the top of the page. Currently, I have implemented a straightforward test called inRange function inRange(el, from, to) { var top = el.offs ...

Retrieving Information and Categorizing by Date using Laravel

Running a website where users can access hotlinks for stored images poses an interesting challenge. I am looking to gather data from the past 7 days in my image database table, specifically focusing on the 'created_at' column. The goal is to comp ...

Using Vue and PHP to parse a JSON string and display it as a table

I am currently facing a challenge in parsing a JSON string from my Laravel application to my Vue view. The format of the JSON string could be as follows: { "1":[ { "row":"Some text here on first column." }, { "row":"And more text. Second row ...

Guide to connecting a value within a component to an element in App.vue

I'm looking to dynamically assign a class to an element in App.vue based on a property or value from each page component. It's kind of like the opposite of passing a prop, not quite child -> parent or parent -> child. I've tried using ...

The attempt to create the property 'and_ff' on the string 'and_chr 89' has failed

Encountering an issue with a Lambda function, I receive an error that does not occur when running the same code within an Express app. I'm puzzled. Data returned by caniuse.getLatestStableBrowsers(); [ 'and_chr 89', 'and_ff 86& ...

Top storage solution for ExpressJS in the world of NodeJS

Embarking on the journey of creating my first substantial NodeJS application. My primary focus is achieving top-notch performance as the project involves a large AJAX (AngularJS) interface with numerous requests from multiple users. Currently in the proce ...

Is there a way to make the primary button on the previous page function correctly again, just like it did before it was clicked?

Issue Description: I am facing an issue on the order page where I need to link the "Continue" button to a booking page. After reaching the booking page, I expect users to be able to navigate between the two pages seamlessly even when they use the browser& ...

Using NextJS to navigate user journey by mapping an array of values from Formik to

I really appreciate all the help I've received so far, but I'm facing an issue trying to map an object with an array within it to the router. Here is my current code: const initialValues = { region: query.region || 'all', campt ...

Looking to implement the v-model with a bootstrap-vue b-form-radio on a webpage? Here's how you can

bootstrap-vue When the server side sends me the N categories for radio button groups in JSON format, users will be prompted to rate each category as a priority - high, medium, or low. I need to dynamically generate radio button groups for each category to ...

Reactjs throwing an Unsupported Media Type error with code 415

I am currently working on implementing a delete function to remove banner images. Here is the code snippet for my delete function: const [del, setDel] = useState([]); const DeleteBanner = async (banner) => { setDel(banner); ...

Tips for saving and accessing Shopping Cart items using localstorage

As I develop a shopping cart for an e-commerce site, I aim to utilize browser localstorage to store the products. The functions that have been added to my code include: - addToCart(): triggered when the "Add to Cart" button is clicked. - addProduct(): ...

How can JavaScript Regular Expressions be used for Form Validation?

For my registration form, I am including fields such as userid, name, email, password, confirm password, and affiliation. Using regular expressions in JavaScript, I am validating these fields. I am attempting to display any validation errors within the for ...

Tips for preventing a component from updating state prior to data retrieval?

I have a specific scenario where I am working with a page that consists of two components. In this setup, I am retrieving data from the root component and passing it to the child component using the react-redux library. However, I encountered an issue wher ...

Errors encountered by the Chrome extension

Hey there, I've recently delved into creating a chrome extension but hit a roadblock. My issue revolves around the service worker registration failing and encountering errors related to undefined properties. https://i.stack.imgur.com/bGzB4.png The c ...

Nested Promise.all within another Promise.all appears to terminate prematurely, triggering a warning indicating failure to return from a promise

I am utilizing this function to be invoked within another Promise.all. However, I consistently encounter a warning message: Caution: a promise was generated in a handler but was not returned from it. Additionally, the function deleteFutureAppointments() ap ...

Custom font not displaying on Chromecast receiver app

I have followed the specified steps to incorporate a custom font into an html canvas text field. Interestingly, the font displays correctly when accessed on the Desktop Chrome browser, but on the Chromecast receiver application, the font fails to load. Wha ...

handling component interaction with react-redux store

Currently, I am in the process of developing my first significant project using react-redux. While trying to establish state mapping between components in react-redux, I seem to have missed a crucial step. Almost everything is functioning smoothly except ...

Choosing an element beneath a table row using a different element as a reference

I'm attempting to identify the checkboxes associated with the link containing delete.jpg. Here's what I've tried so far: <table> <tr class="odd"> <td><input id="cbox1" type="checkbox"></input></td> ...

How do I access and read a map within an array from Firebase using ReactJS?

I have an array that contains a map with two values: title and content. https://i.stack.imgur.com/WLWVG.png I am trying to read all the values in the array as if it were a map. However, I have attempted this code without success. Can anyone assist me? {d ...