Viktor Korai
Viktor Korai

Reputation: 197

Vaadin 14 Springboot javascript does not work

I'm trying to develop my first Vaadin 14 application, I'm also using Spring boot framework for it. I've created a javascript file, I put it into the folder frontend/src with the name of teams.js and I'm trying to import it with @JsModule("src/teams.js"). My root view class looks like this:

@Route("")
@PageTitle("Teams organization store init")
@Slf4j
@JsModule("src/teams.js")
@Tag("TeamsEntry")
public class TeamsEntryView extends VerticalLayout implements BeforeEnterObserver {

    public TeamsEntryView() {
        initTeams();
    }

    private void initTeams() {
        var ui = UI.getCurrent();
        var page = ui.getPage();
        log.info("Teams initialization...");
        page.executeJs(getTeamsConfig()).toCompletableFuture().whenComplete(((jsonValue, throwable) ->
                log.info("Teams initialization completed: {} with throwable {}", jsonValue.toJson(), throwable.getMessage())
        ));

    }

    private String getTeamsConfig() {
        return """
                console.log('ss');
                window.initTeams();
                console.log('xx');
                return true;
                """;
    }
...

My js file looks like this:

window = {
    initTeams: function () {
        console.log('initTeams...');
    }
}

In this case, I see "ss" in the browser's console, but nothing more. If I remove the window.initTeams(); line I get "ss" and "xx" as well. If I declare a simple function in the js file and call it without the "window" class I get similar results. If I use @Javascript or page.addJavascript("src/teams.js") I get this error when the page loads: "> unexpected character" If I try to call join() or get() on the completable future the browser freeze. If I use @Javascript("frontend://src/teams.js") I get some CORS error like if it is trying to download something from the "frontend" host. I've tried to put the @JsModule on a component instead of my view.. it does not work. I've tried to put my js file to the root, and to the resources folder.

I could not find any other solution to import and use my js file into vaadin14 with spring boot. Also, I'm not sure why the browser freeze if I call "join()" on completable future, and also the on the result of it sentToBrowser returns false even if I see the console logs in the browsers log...

Can somebody explain to me how should I do the javascript import, why my current code does not work, and why the "join()" freezes the browser, please?

Thank you in advance!

@Edit

I have also tried with this annotation @JavaScript("./src/teams.js") and a js like this:

    function initTeams () {  
        console.log('initTeams...');  
        console.log("Teams initialized!")  
    }

@Edit

Okay so finally I got it working. The js file has to be under root/src/main/webapp/src folder. Nor @JavaScript and nor the @JsModule worked for me, so I had to import my js file as:

        var ui = UI.getCurrent();
        var page = ui.getPage();
        page.addJavaScript("src/teams.js");

Then I can call it like window.initTeams() or like initTeams() and both works fine. Altough the completable future below still never executes, and isSentToBrowser() always returns false.

page.executeJs(getTeamsConfig()).toCompletableFuture().whenComplete(((jsonValue, throwable) ->
                log.info("Teams initialization completed: {} with throwable {}", jsonValue.toJson(), throwable.getMessage())
        ));

I must mention if I start the path with '.' like page.addJavaScript(".src/teams.js"); then it does not find the file.

Does anybody have an answer, why the completable future never executes?

Upvotes: 3

Views: 664

Answers (1)

Oliver
Oliver

Reputation: 1645

The problem is that the following code redefines the window object:

window = {
    initTeams: function () {
        console.log('initTeams...');
    }
}

Did you meant to add a function to the window object? Like so:

window.initTeams = function () {
    console.log('initTeams...');
};

If you want to keep code visually similar to yours:

window = {
    ...window,
    {
        initTeams: function() {
            console.log('initTeams...');
        }
    }
}

Other options:

window['initTeams'] = function() {...}
Object.assign(window, {initTeams: function() {...}})
Object.defineProperty(window, 'initTeams', {value: function() {console.log('foo')}});

Gotta love JavaScript...

Also, for more knowledge, the code mentioned in your @Edit section could not be called. Calling initTeams() is equivalent to window.initTeams(). The function must exist in the window object. This is why, for example, you see some custom elements defined like customElements.define(...) and window.customElements.define(...).

Upvotes: 3

Related Questions