3

I am using j2html to create render html pages via Java, if the html called any javascript function I was putting the Javascript into a separate .js file. However it seems sensible to only include functions is the main application javascript file if they are general purpose functions used by multiple pages. A function written specifically for one page shod be stored somewhere else, creating separate .js files for each page is an administrative nightmare so I want to put them into the html itself near the calling code.

I can do this easily enough, and below is an example created by copying function directly from .js file and wrapping within j2htmls script and rawHtml tags. My problem is that the Javascript code within my Java code is not as readable as it is when within the seperate js file.

Is there any way I can write it in a neater more readable way ?

private Tag artwork()
{
  return script(rawHtml("function artwork() {\n" +
          "    \n" +
          "    select   = document.getElementById('fsArtwork');\n" +
          "    selected = select.options[select.selectedIndex].value;\n" +
          "    if(selected==0)\n" +
          "    {\n" +
          "    \tdocument.getElementById('saveArtworkFilename').disabled = true;\n" +
          "    }\n" +
          "    else\n" +
          "    {\n" +
          "    \tdocument.getElementById('saveArtworkFilename').disabled = false;\n" +
          "    }\n" +
          "}"));
}

In the comments below I keep getting asked why I don't want to use templates , there are a number of reasons:

My webpages are not currently created with templates so it would seem if I wanted a html page with some javascript in it and used templates as suggested I would have to redo the whole page using templates

Since I wouldnt want to write my html in multiple different ways I would be duty bound to redo all my pages in templates

So why didn't I used templates in the first place ?

First of all the main advantage of templates is to separate what the web-developer does from the server developer. I am doing both so there is not an advantage for me. I use a separate stylesheet so if at a later date I want a web-designer to improve the look by modifying the style then they can do that, templates dont help.

Another advantage is code readability, this what certainly true when comparing jsps to servlet code but is not true when comparing to j2html. This lib ensures I can only create wellformed code, and that I can take advantage of Java for creating dynamic and data based pages much more easily then templates.

Using templates would require learning their esoteric ways

Using templates would complicate build and deployment

Webpages generated from templates is considerably slower than pure Java, from j2html website You think template engines are too slow. This index page was rendered 100 000 times in less than a second on an i5-4670. That's about a thousand times faster than Apache 'Velocity' (hah!)

Trying Tipsy's answer

When I try to generate the page it complains

Couldn't find file with path='javascript/artwork.js'

My code contains the existing external files initilization and a location within the main classpath (newly added). Is it okay to have both.

    staticFiles.externalLocation(Platform.getPlatformReportFolder().getPath());
staticFiles.location("");

scriptWithInlineFile_min("javascript/artwork.js"),

Within the main jar file (songkong-4.13.jar) that contains the manifest the javascript file is located within javascript folder which is top level folder within the jar.

I do notice that within the manifest songkong-4.13.jar itself is not listed in the Class-path, this have never been an issue but could that be the issue now ?

Also within my Intellij project itself the javascript folder is in src/main/resources, this seemed to be the default but it would not work running within IntelliJ either.

Now working in Dev

The problem was that I was using a relative path

scriptWithInlineFile_min("javascript/artwork.js")

instead of

   scriptWithInlineFile_min("/javascript/artwork.js")

So it now works in dev.

But when I build it and run outside of dev it is not finding the file again, even though it there in the main jar file directly as /javascript/artwork.js

Further Update

It was a bug in j2html https://github.com/tipsy/j2html/issues/84 but was fixed in 1.2.1 and I was using 1.2.0, now everything is working.

In Summary

I don't know if you would call this templating or not but works perfectly for me. The page specific javascript can be written in file, but then embedded into the rendered html file , and because in main jar no additional deployment issues that you would have if actually deployed as standard files.

Paul Taylor
  • 13,411
  • 42
  • 184
  • 351
  • Yeah, don't write HTML in Java. Put it in a template. – Dave Newton Jan 25 '18 at 15:05
  • 1
    Html is not the issue, j2html works great and is much better than templating solutions, the issue is specific to javascript within the html – Paul Taylor Jan 25 '18 at 15:27
  • Irrelevant; it's still going to the browser, it doesn't matter which it is. You put it in a template. As to whether or not h2html is "much better than templating solutions", that's an opinion, one I don't share: I'd rather write HTML in an HTML-aware editor with HTML attribute completion etc. Neither here nor there--any time you're trying to write one language in another you'll end up with an impedance mismatch. Put the JS in a file and send the file contents. – Dave Newton Jan 25 '18 at 15:35
  • Html editor fine for basic static webpages but when you are creating dynamic pages then j2html is much beter than any templating solution I have tried, you should try it. Anyway what is irrelvant is diuscussing html as my answer is specifically about Javascript, – Paul Taylor Jan 25 '18 at 18:55
  • Still belongs in a file. Every page I make is dynamic-but there are much easier Solutions available. ¯\_(ツ)_/¯ – Dave Newton Jan 26 '18 at 00:26
  • So you never have javascript functions within the html page itself ? – Paul Taylor Jan 26 '18 at 07:31
  • Very rarely. But even if you insist on not templating you're still just writing a string. Put it in a file, load it at startup or lazily and cache. – Dave Newton Jan 26 '18 at 11:50
  • 'Put in a file' is a naive solution, if you look at my example above you see there are variables such as fsArtwork and saveArtworkFilename these are ids of element referred to in the Html, these ids are properly defined in my java server code so I could use the variable when constructing Html and javascript so that if I wanted to change name I just need to in one place in Java code, with your solution I would have to remember to modify all my javascript files as well. – Paul Taylor Jan 26 '18 at 12:01
  • No, they’re in a template. This is a problem that was solved two decades ago. I don’t see any issue at all. – Dave Newton Jan 26 '18 at 14:02
  • So when you put in a file you mean put in a template,my question was not how do I use templates. There are good reasons not to use templates so if you cannot understand help me with the question just leave it be because USE TEMPLATES IS NOT AN ANSWER TO MY QUESTION – Paul Taylor Jan 26 '18 at 14:35
  • Lol sure, ok. You should probably update the question to explain why templates aren’t an answer to your question, because it’s the canonical solution. The days of doing lots of client-side work on the server side are long gone (except for pre-rendering, I suppose) as are the days of worrying (much) about saving 10k of gzipped source. Shrug. Good luck! – Dave Newton Jan 26 '18 at 14:46
  • Yes you are continually misunderstanding, Im not doing client-side work on the server, and Im not worrying about saving 10k of source, neither point is at all relevant here. – Paul Taylor Jan 26 '18 at 14:57
  • You're creating JavaScript to send to the client. That's client-side work. It mixes concerns. The canonical solution is a template, and so far you've provided no information regarding why that isn't a good solution. ¯\(°_o)/¯ – Dave Newton Jan 26 '18 at 15:39
  • Im constructing webpages dynamically from server, they are not physical files. Im doing this using https://j2html.com/ and serving using http://sparkjava.com/, that is a perfectly valid solution and one Im happy with ,and im finding it much more productive then using a templating technology like jsp or velocity. the only thing I dont like is when I want to include local javascript. I'm not going to rewrite my whole application just so i can use templates for javascript, do you understand now ? – Paul Taylor Jan 26 '18 at 16:32
  • Nope. You have a hardcoded string (that happens to be JS) that you could put in a file, load, and send. Even if there were templating to be done I'd *still* use a template instead of constructing it in Java. This allows hot-deploy of your JS to fix JS-related issues, allows editing it in a normalized way, and so on. I certainly wouldn't write it as shown in the question--for formatting purposes what I'd do is in an answer, but it doesn't answer your question--just more convenient than a gist. – Dave Newton Jan 26 '18 at 16:56
  • Clearly this isnt the whole page, the question was about javascript within html page, I didnt show html for clarity, your use of an array is an improvement on my approach (albeit minor) – Paul Taylor Jan 26 '18 at 17:39
  • Where the string gets shoved doesn't seem relevant-you have a method returning a string. Where that string comes from or how it's constructed isn't relevant to consumers of the method. – Dave Newton Jan 26 '18 at 18:09
  • I know, no idea what your point is. In your answer you say you barely remember Java, and I think that is the point, you dont really understand the Java ecosystem so not the right person to answer this question, I was looking for approaches taken by current Java developers. – Paul Taylor Jan 26 '18 at 18:15
  • Not remembering language specifics is a lot different than not knowing an ecosystem-I work in the ecosystem daily, but rarely code Java directly anymore beyond API endpoints. What I *do* know is the web ecosystem and what solutions are the best fit for specific problems. You are unwilling or unable to define what about templates are bad. You know what solutions are used by current Java web developers for templated content? Templates. Creating client content through Java code died when JSP appeared, though there are better solutions now. Why are templates inappropriate? – Dave Newton Jan 26 '18 at 18:49
  • 'Java code died when JSP appeared', yes but since then JSP has died out, you are talking about things you dont really know about, my question was how to code Javascript within Java code, why am I having to waste my time explaining to you why templating doesnt work for me, perhapos you should post a question yourself if you are interested in that. – Paul Taylor Jan 26 '18 at 21:07
  • You're asking for how to generate JavaScript in Java. The canonical answers are (1) you don't, and if you must, (2) templates. Since those are the canonical answers, it would behoove you to provide a reason why the canonical answers are not applicable in your situation to avoid people reiterating the cnaonical answers. You refuse to do this, for whatever reason. ¯\(°_o)/¯ JSP's utility is irrelevant--my point was that generating client-side code from Java code died a long time ago, for good reasons. – Dave Newton Jan 26 '18 at 21:27
  • As to questioning whether or not I know what I'm talking about, that's outside the bounds of SO discourse. I know quite a bit about what I'm talking about, but you're unwilling to actually define the explicit problem you're having. So again, good luck. – Dave Newton Jan 26 '18 at 21:28
  • You say 'my point was that generating client-side code from Java code died a long time ago, for good reasons' you then say you havent used Java for a long time so how do you know the current state, you have given no evidence to back up your assertion. It seems you are pushing your 'canonical answer' rather than trying to answer my question. But I briefly add to the question why I dont want to use templates. – Paul Taylor Jan 26 '18 at 21:36
  • What I said was that I rarely write Java code directly. Because I have people that write the Java code for me. I'm still heavily involved in the ecosystem and the development of Java-based web apps, APIs, and Big Data solutions. Don't assume that because people don't write in a particular language on a daily basis that they're ignorant. I *can't* answer your question without understanding why the canonical solutions aren't appropriate. – Dave Newton Jan 26 '18 at 21:38
  • (Unrelated, but I'd also argue against bothering with hyper-localizing JS code; the most common JS-based client-side frameworks ship the entire app in a single bundle, and use other mechanisms to understand when to run page-specific JS.) – Dave Newton Jan 26 '18 at 21:39
  • Ive added reasons why I dont want to use templating – Paul Taylor Jan 26 '18 at 21:48
  • (Velocity is probably one of the slowest templating engines around, btw.) The old Google project that let you write JavaScript in Java might be a starting point, but I doubt it. In any case, pre-compiling templates will generate essentially the same Java code you'd write manually, and allow per-render customizations. It's still just a function returning a string, and I don't see any benefit to generating JS source via pure Java. I don't know why you'd have to redo anything other than move the JS into files, pre-approval load them, and have your JS functions use that. YMMV. – Dave Newton Jan 26 '18 at 23:36
  • and where do I store these Javascript files, I have already explained the hassle of having to deploy these extra files, remember this is a standalone Java application running with a html frontend, its not running with a servlet engine. – Paul Taylor Jan 29 '18 at 13:32
  • You store them as resources in your app. The templates are not deployed--they're templates. The templates are pre-compiled and rendered in your existing Java application, and sent as a string the exact same way you're doing it now. – Dave Newton Jan 29 '18 at 15:24

2 Answers2

3

I think you should write your JavaScript in .js files. Include them either via script().withScr("/path/to/file.js") (if the file is hosted), or via scriptWithInlineFile_min("/path/to/file.js") (if you want to read the file from the classpath/file-system).

tipsy
  • 402
  • 4
  • 15
  • So if I understand you right as long as your .js is within your main jar and its path is valid within that jar relative to the staticFiles.location() then the generated html page will contain the contents of the javascript directly within the html page (rather than a link to an external js file) without me having to directly put the javascriupt within the j2html java page itself. Sounds perfect, cant get it working at the moment though, Im updating my question to show the error. – Paul Taylor Jan 30 '18 at 11:55
  • Ive marked as correct as seems like right answer, but still cannot get it to work – Paul Taylor Jan 31 '18 at 09:46
  • 1
    If you're using `scriptWithInlineFile_min(...)` you don't need to use `staticFiles.location(...)`. `scriptWithInlineFile_min(...)` reads the file from the classpath/file-system and returns it as a String. You can have a look at the tests for this method to see how it works: https://github.com/tipsy/j2html/blob/master/src/test/java/j2html/tags/InlineStaticResourceTest.java – tipsy Feb 01 '18 at 18:35
  • The problem I was using a relative path scriptWithInlineFile_min("javascript/artwork.js") instead of scriptWithInlineFile_min("/javascript/artwork.js"), it now works. Files are stored under resources in my maven project) – Paul Taylor Mar 14 '18 at 12:06
  • Also I was using j2html 1.2.0 that has a bug that prevents reading resources from jar file so that prevented working in production, updating to 1.2.2 fixed the issue. – Paul Taylor Mar 14 '18 at 19:27
0

(Delta I barely remember Java, and I know you don't need some sort of StringUtils to join anymore.)

private Tag artwork() {
  String[] js = [
    "function artwork() {",
    "  select   = document.getElementById('fsArtwork');",
    "  selected = select.options[select.selectedIndex].value;",
    "  if (selected === 0) {",
    "    document.getElementById('saveArtworkFilename').disabled = true;",
    "  } else {",
    "    tdocument.getElementById('saveArtworkFilename').disabled = false;",
    "  }",
    "}"
  ];

  return script(rawHtml(StringUtils.join(js, "\n")));
}

But I'd still put it in a template, load and populate, and ship that to the client. The code generated by any reasonable template engine will end up being almost this anyway.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302