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?
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(...).
Related
I have a file containing the definition of a Object and in that same file I have a function that is part of this object like so:
export function ARScene(_callbacks) {
this.callbacksObject = _callbacks;
// more fancy code..
}
ARScene.prototype.changeCar = function() {
//some fancy code here
this.loadHDCar(); // THIS LIKE GENERATES A ERROR.
}
now I have a different file containing an other method that is part of the Object called ARScene like so:
import { ARScene } from './arScene';
ARScene.prototype.loadHDCar = function() {
//some more fancy code..
}
What is happening when I build this with webpack and run it in the browser I get the error that this.loadHDCar(); is undefined I guess this happens because webpack doesnt add a file if it is not imported. But how do I make sure that ARScene.prototype.loadHDCar is added to the object in the final output?
I am a complete newbie to webpack and modules. I have found answers on stackoverflow about this but they had slightly different scenarios then me. So their solutions didnt work (or maybe I didnt understand it).
If more context or information is needed please let me know.
How do I make sure that ARScene.prototype.loadHDCar is added to the object in the final output?
You should import it in the arScene module, and you should even create the prototype method in there (where you are defining the class) for visibility.
export function loadHDCar() {
… //some more fancy code
}
import { loadHDCar } from './loadHDCar';
export function ARScene(_callbacks) {
…
}
ARScene.prototype.loadHDCar = loadHDCar;
ARScene.prototype.changeCar = function() {
… // some fancy code here
this.loadHDCar();
};
I'm moving my nodejs project from Javascript to Typescript. It's going to be a slow process, slowly changing things over a few months as i need to tweak stuff.
I've created a typescript class that looks something like this:
// RedisRepository.ts
export class RedisRepository {
public async getDevice(serial: string) : Promise<Device> {
// blah
return device;
}
}
Then in another Javascript file where i need to reference and then call the functions on the above class.
// ExpressApi.js
const repository = require('../Redis/RedisRepository');
async function getRedis(req, res) {
try {
const device = await repository.getDevice('serialnumberxxx');
res.status(200).end(JSON.stringify(device ));
} catch (e) {
logger.error(e);
res.status(500).end();
}
}
however, when it tried to call the function on the repository it says it doesn't exist. Using chrome debugger, i can see that it exists at: repository.RedisRepository.prototype.getDevice. This doesn't seem the correct way to use the function though.
While I appreciate I could just convert ExpressApi.js to Typescript. I'm going to have this problem with many different files. So i need to use it as JavaScript for now. I'll slowly continue to go round the project and change things to Typescript.
As #crashmstr mentioned, you should create a new instance of RedisRepository, then call getDevice method.
If you still want to use
const repository = require('../Redis/RedisRepository');
syntax, you could export default new RedisRepository() from your RedisRepository.ts file.
I get an error in my console when I try to create a type script file from a partial view (MVC .NET) which is loaded by a rest call and appended to a div element.
I get: Uncaught ReferenceError: xyz is not defined.
in my partial view i have below code:
<script type="text/javascript">
$(document).ready(function () {
var model = #Html.GetJson(Model.x);
var view = new xyz.ExceptionView();
view.init();
});
</script>
Edit: I added "#section scripts {}" around my script tag and then i get nothing in my console and no execution or logging from implementation
And I forgot to mention that my TypeScript file is not implementing anything. But here it is.
Is this not a correct way of using typescript?
module xyz {
export class ExceptionView {
constructor() {
debugger;
}
public init = (model: any): void => {
debugger;
}
}
}
As you can't include or reference TypeScript directly in your HTML, I assume you have a script tag that includes the compiled JavaScript? Does the JavaScript emitted from the TypeScript compilation look right? Are you able to step through the final JavaScript code in the browser Web Developer Tools and see where the breakdown is occurring?
i am writing a test class
class ListOfProjectsSpec extends GebReportingSpec{
def "project dashboard filters are instantiated correctly" () {
given:
at ProjectIndexPage
expect:
projectTable != null
}
}
to test functionality of my ProjectIndexPage.
class ProjectIndexPage extends ProjectsCategoryPage{
static at = {
$("title").text() == "Title"
}
static content = {
projectTable {
$("table.dynamic-projectTable")
}
}
}
(i cleaned up a lot of code to show the simplest case only).
complication
the class dynamic-projectTable is added at runtime to the table with jquery/javascript in as an acessor for filters on the page.
<g:javascript>
$(
$('#projectTable').addClass('dynamic-projectTable');
});
</g:javascript>
error
junit.framework.AssertionFailedError: geb.error.RequiredPageContentNotPresent:
The required page content 'projectTable- SimplePageContent (owner: ProjectIndexPage, args: [],
value: null)' is not present
additional info
when looking at the html output of the spock test it is clear that the dynamic-projectTable class is not added (as are all other actions performed by the $() jquery call - i removed them here to make the example more readable)
i tried
// calling the document.ready function explicitly in my test cases
when:
$("document").ready()
enabled javascript
driver = {
HtmlUnitDriver driver = new HtmlUnitDriver();
driver.setJavascriptEnabled(true);
driver
}
but nothing seems to work.
any input?
Pages built by javascript often require Geb to wait for the content to be rendered.
See http://www.gebish.org/async for details.
Basically, I'd try explicitly waiting in your spec code:
waitFor { projectTable }
Waits can also be configured on the page content:
projectTable(wait: true) {
$("table.dynamic-projectTable")
}
i was able to solve it by explicityly re-enabling javascript in the testSpec:
def setup() {
if (driver instanceof HtmlUnitDriver) {
driver.javascriptEnabled = true
}
}
To avoid issues like this it is better to define more applicable at checks.
In your example you have used:
static at = {
$("title").text() == "Title"
}
Try checking for something which will be used in the tests. E.g A form element. I would also use a waitFor closure in the at checker so all pages after a to call will be ready for testing.
static at = {
waitFor { $('#projectTable').#class.contains("dynamic-projectTable") }
}
I'm having a problem since I wrapped my javascript functions inside of a namespace.
Version 1 of my code worked fine. Originally, to call the javascript from inside Silverlight I used to use this code:
HtmlPage.Window.Invoke("hideMyDiv");
My javascript looked like this:
function hideMyDiv() {
$('#MyDiv').fadeOut();
}
Now, I've refactored my javascript to be contained in a namespace. So it now looks like this:
var activity = {
message: null,
hideMyDiv: function() {
$('#MyDiv').fadeOut();
} };
I can call this refactored function in javascript, it works like before:
$("document").ready(function() {
activity.hideMyDiv(); });
But when I try to use it from Silverlight, I get this error: Failed to Invoke: activity.updateInfo. This is my current Silverlight code:
HtmlPage.Window.Invoke("activity.hideMyDiv");
What am I doing wrong? (and thanks!)
This is the correct way..
ScriptObject so = HtmlPage.Window.Eval("activity") as ScriptObject;
so.Invoke("hideMyDiv");