injecting ejs with a client-side variable - express

My express router is making available an object on my ejs template called inventory.
My client side is doing a ajax request that returns an object called result.
I want to put the value of result object into my ejs tag. How can I do this?
<%= inventory["result[x].variation_identifier"].price %>

You cannot. The values inside the EJS tags are calculated and rendered as strings into the markup on page load. What I would suggest that you do is wrap this EJS in another element, then change that element's innerText in the callback of your AJAX request. In turn, I must advise you to avoid turning around and using hard-coded values in your markup to perform other calculations or requests.

Related

Render non-vuejs HTML in a component

I have a working VueJS app with nested components.
In one of the components, I want to be able to inject arbitrary HTML but I don't want VUEJS to parse it : I want plain old HTML tags (scripts, iframes, style, divs, native events, whatever I need).
I know I can do that outside the root "#app", but is there a way to do that inside it ?
Thanks.
You can use v-html directive, it takes an expression that evaluates to a string and sets the element's innerHTML to that string. Vue won't parse it as a template and insert it into the DOM instead. This is one of those things that you need to pay attention to security for.
See docs: https://vuejs.org/api/built-in-directives.html#v-html

RiotJS mounting tag without subtags

I am using tag-based routing with RiotJS. If the tag in the route contains an other tag, it is automatically mounted. Which is great in some cases. But there are cases when I need to pass some options to the tag being mounted, that can't be passed as tag property. I know that this.tags will contain them and I have the means to pass that parameter afterward. But I still am curious if there is a way to stop RiotJS automounting some subtags.
Sounds like you have a design error.
Remember that a tag can contain any classic JS code; you can simply write a logic that populates the tag in any time, way, shape or form. You can also hide it's content via the if condition until it is populated, while it is mounted. You can also hide it in the parent and prevent its mounting in the same manner if you so desire.

Server Side Rendering Vue with ASP.NET Core 2

I'm trying to understand the usage and limitations of server side rendering with vuejs when using aspnet core.
I used this starter kit for aspnet core and vuejs to setup a simple vue site, which is running based on the code here: https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/master
I then modified the project to update the aspnet-prerendering and added vue-server-renderer, compiling a hodgepodge of sources to cobble together this update: https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/ssr
If I run this project, the site appears to load fine, and if I turn off the javascript in the browser, I can see that it does appear that the server-side rendering executed and populated the html result:
however, because JavaScript is disabled, the content isn't moved into the dom as it looks like it is trying to...
My understanding of server-side rendering is that it would populate the html entirely and serve a completed page to the user, so that even if JS was disabled, they'd at least be able to see the page (specifically for SEO purposes). Am I incorrect?
Now I believe modern search engines will execute simple scripts like this to get the content, but I still don't want a blank page rendered if js is disabled...
Is this a limitation of server-side rendering, or perhaps specifically ssr with vue and/or aspnet core?
or am I just missing a step somewhere?
Edit: more information
I looked at the source code for what I believe is the method that prerenders the section here: https://github.com/aspnet/JavaScriptServices/blob/dev/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs
The line
output.Content.SetHtmlContent(result.Html);
has a null value for result.Html. However, when I manually edit this value to put a test value, it also doesn't render to the output html, and the app div tag is still empty...
If I'm doing something wrong to populate the result.Html value with the expected output, that's one thing, and I would appreciate some help in doing that, especially since the output html appears to be found, since it's in the script that immediately follows...
However, even if I were to populate it, it appears it's being skipped, as evidenced by me manually changing the value. is this a bug in the code or am I doing somethigng wrong, or perhaps both?
As you correctly noticed, for your project, result.Html inside the tag helper is null. So that line cannot be the location where the output is being generated. Since the HTML output from your prerendering script also does not include a script tag, it is clear that something has to generate that. The only other line that could possible do this is the following from the PrerenderTagHelper:
output.PostElement.SetHtmlContent($"<script>{globalsScript}</script>");
That would fit the observed output, so we should figure out where the globalsScript comes from.
If you look at the PrerenderTagHelper implementation, you can see that it will call Prerenderer.RenderToString which returns a RenderToStringResult. This result object is deserialized from JSON after calling your Node script.
So there are two properties of interest here: Html, and Globals. The former is responsible for containing the HTML output that finally gets rendered inside the tag helper. The latter is a JSON object containing additional global variables that should be set for the client side. These are what will be rendered inside that script tag.
If you look at the rendered HTML from your project, you can see that there are two globals: window.html and window.__INITIAL_STATE__. So these two are set somewhere in your code, although html shouldn’t be a global.
The culprit is the renderOnServer.js file:
vue_renderer.renderToString(context, (err, _html) => {
if (err) { reject(err.message) }
resolve({
globals: {
html: _html,
__INITIAL_STATE__: context.state
}
})
})
As you can see, this will resolve the result containing just a globals object with both html and __INITIAL_STATE__ properties. That’s what gets rendered inside of the script tag.
But what you want to do instead is have html not as part of globals but on the layer above, so that it gets deserialized into the RenderToStringResult.Html property:
resolve({
html: _html,
globals: {
__INITIAL_STATE__: context.state
}
})
If you do it like that, your project will properly perform server-side rendering, without requiring JavaScript for the initial view.

Rendering an aurelia custom element in ag-grid header

Is there an "easy" way to render a custom element in ag-grid header cell? The headercomponent interface seems like an overly cumbersome approach to a seemingly simple problem and I have not been successful with this approach. The closest I have come is to use something like:
header-cell-render.bind="myHeaderRenderer"
which is currently a function returning a string of HTML. While this "works" (though I understand it is deprecated), in the sense that the html is injected into the DOM, only primitive HTML renders. Meaning I can return something like:
<input type="checkbox" />
and it will render a checkbox, but I cannot return something like:
<my-custom-element></my-custom-element>
I can see that markup in the DOM, but the element doesn't "process", that is the Aurelia aspect of the control is not executed.
I am using the latest versions of ag-grid, ag-grid-aurelia.
Any help would be greatly appreciated.
This is currently not possible out of the box with ag-grid-aurelia.
This is because ag-grid-aurelia makes no special handling for this binding. The proper way to handle this is using replaceable parts which allows you to specify a template for Aurelia to inject and consume. ag-grid makes this a bit harder since it seems the only native tool for injecting content into the header is by passing an HTML string or an HTML element in the column configuration. This can likely be added to the ag-grid-aurelia library by using a combination of replaceable parts and the #children decorator to gain access to the aurelia-rendered header element and pass it to the column configuration.

How to get a data on the client side with javascript from the render express method?

I use to work with MVC javascript framework such as Backbone or Angular, i would like to fully use express and there is something i don't know how to do.
When i used javascript client framework, i made AJAX GET calls to get my entities from express with res.send(), but only with the express rendering engine, how to get the entity you send with res.render('index', { User: { name: 'bob' }}) on the client side in your javascript code?
I tried on the client side to directly call:
<script>
console.log(JSON.stringify(User));
</script>
But i get a Uncaught ReferenceError: User is not defined
However, i can access the object in my html using ejs:
<h1><%= User.name %></h1>
I know how to get it in the html using the ejs view engine, but how to get it directly from the javascrit ?
Are you looking for something like client side rendering? Then RequireJS is the thing for you. res.send sends the data back to the client javascript framework and res.render renders a page or a template. Do let me know if you require something else.
Answering this much later, but I ran across this issue and had to work with it for quite a while before I got it, thought I would share for future visitors of this question.
Like V31 said earlier, res.render renders the template without passing the data first in JavaScript. The variables like <%= User.name %> only refer to their server-side definition as long as your EJS template is actually an EJS template -- which it stops being once it's been rendered as the page. As the Express docs say, render "returns the rendered HTML of a view." In other words, saying console.log(User.name) client-side is trying to access an object that only exists in the server.
You can get around this like this:
<script>
console.log('<%= JSON.stringify(User) %>');
</script>
With the quotes required around the <%= JSON.stringify(User) %> because this result will be a string rather than a variable -- you don't want your console.log treating the entire stringified user data as a variable, you just want to log it.
Taking this concept further, this is how one would make variables you're passing into your render accessible to client-side JavaScript files as well. For example, say you have a document.onLoad function that requires a variable from the server to decide whether or not to make a particular DOM manipulation.
<script>
const bob = '<%= User.name %>';
const alice = '<%= User.bestfriend %>';
</script>
<script src='/javascripts/myscript.js'></script>
myscript.js now has access to User.name and User.bestfriend as they were defined in the server's User object, and can use that data client-side in whatever manner you see fit.