How to show autocomplete for user mentions in TextArea

Sometimes we need to implement Twitter-like user mentions in text areas:

image

Here you will see how to integrate a third-party JavaScript extension, such as Mention.js.

First of all, you will need to create VAADIN directory in modules/web/web and copy all your JS/CSS assets there.

image

Then declare Java class for your extension in web module sources:

package com.company.demo.mentionjs;

import com.haulmont.cuba.web.widgets.WebJarResource;
import com.vaadin.annotations.JavaScript;
import com.vaadin.annotations.StyleSheet;
import com.vaadin.server.AbstractJavaScriptExtension;

import java.util.List;

@JavaScript({
        "vaadin://mentionjs/bootstrap-typeahead.js",
        "vaadin://mentionjs/mention.js",
        "vaadin://mentionjs/mentionjs-extension.js"
})
@StyleSheet("vaadin://mentionjs/bootstrap.min.css")
@WebJarResource({
        "jquery:jquery.min.js"
})
public class MentionJsExtension extends AbstractJavaScriptExtension {
    // extension requires Vaadin TextArea
    public MentionJsExtension(com.vaadin.ui.TextArea target) {
        super(target);
    }

    // API of our extension
    public void setUsers(List<String> logins) {
        getState().logins = logins;
    }

    // override getState methods to enable custom state POJO
    @Override
    protected MentionJsState getState() {
        return (MentionJsState) super.getState();
    }

    @Override
    protected MentionJsState getState(boolean markAsDirty) {
        return (MentionJsState) super.getState(markAsDirty);
    }
}

Here we define all the required CSS/JS resources using @JavaScript and @StyleSheet annotations. Also, we need custom POJO that will represent state of the extension (it will be passed to JS side):

public class MentionJsState extends JavaScriptExtensionState {
    public List<String> logins;
}

After that we can define JS side in mentionjs-extension.js:

// entry point of client side code
// function should be named as FQN of the corresponding Java class
window.com_company_demo_mentionjs_MentionJsExtension = function () {
    var self = this;
    var textArea = self.getElement(self.getParentId());

    // subscribe on state change from server
    self.onStateChange = function () {
        var logins = this.getState().logins;
        if (logins) {
            var users = [];
            for (var i = 0; i < logins.length; i++) {
                users.push({username: logins[i]});
            }
            // call mention JS code
            $(textArea).mention({
                delimiter: '@',
                users: users
            });
        }
    };
};

This code will be loaded and executed after JavaScript extension added to TextArea.

Now, we can enable extension in UI screen as follows:

public class DemoScreen extends Screen {
    @Inject
    protected TextArea<String> messageArea;

    @Subscribe
    protected void onInit(InitEvent event) {
        // get Vaadin UI component from CUBA class
        com.vaadin.ui.TextArea vTextArea = messageArea.unwrap(com.vaadin.ui.TextArea.class);

        // enable extension
        MentionJsExtension extension = new MentionJsExtension(vTextArea);
        extension.setUsers(Arrays.asList("Peter", "Lilith", "John", "Mathew", "Alex"));
    }
}

It will look like:
image

You can find the sample code here: GitHub - cuba-labs/user-mentions: How to enable Twitter-like user mentions in TextArea using Mention.js

JavaScript extensions enable you to apply JS code to the existing UI components, e.g. inputs, labels, buttons, etc. Read more about JS integration here: Integrating JavaScript Components and Extensions | Client-Server Integration | Framework | Vaadin 8 Docs

7 Likes