Passing collection parameters when calling templates in StringTemplate - stringtemplate

Run into a bit of a snag using StringTemplate today. Were using StringTemplate 3.1 with .Net 3.5.
If I have a template that renders a collection of items, it renders fine if I call it directly.
However, if I call that template from another template and passing the collection through as a parameter, it fails to render at all.
The following is the basic template for rendering the collection. (Text is a property of the object we are rendering - System.Web.Mvc.SelectListItem)
list.st
$values: {
$it.Text$
}$
And this is the calling template.
callsList.st
$list(
values={ $list$ }
)$
My question is, has anyone else run into this or does anyone know how to work around it? The strange thing is, we have other parts of our system rendering in a similiar style and they seem to work fine.

Try values=list.
Terence

Related

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.

Vue JSX bind to class name

I'm building a simple TodoMVC app using Vue + JSX, but the documentation seems to be seriously lacking. Thus, I'm writing down the points I need to address as part of a CR to the appropriate projects. The only document I've read as of yet is the guide, which doesn't cover much JSX at all. I don't know much about how the framework works yet, but I sure prefer using the render method over the string templates for performance/network reasons.
question
What's the proper way to create a class name binding in Vue + JSX? In my TodoItem component, creating either a class or className attribute makes Babel throw a compile error complaining the API is deprecated (and suggesting I add several seemingly unrelated dependencies to the mix). Plus, including the class property in the data object seems to change nothing.
secondary question
The lack of documentation, plus the wording on the guide gives the impression JSX is not the "proper" way to write Vue components. Is that so? What's the idiomatic way to do it, given I don't want to ship the compiler along with my app?
links
code on codepan
I sure prefer using the render method over the string templates for performance/network reasons.
If you're writing *.vue files and bundling them with vue-loader (Webpack), the HTML template gets compiled into a JavaScript render function anyway, so there isn't really any kind of performance issues in that sense.
On the other hand, if you're writing your Vue components with string templates like this:
new Vue({
template: '<div>Hello</div>'
})
then you'll need the Vue template compiler at runtime to convert the string into a render function.
Typically people would opt for writing render functions manually if they need to do something specific that would be difficult/impossible to do with the HTML template alone.
You've probably already read the docs, but just in case, the relevant sections are:
Render Functions & JSX
The Data Object In-Depth
babel-plugin-transform-vue-jsx Usage
What's the proper way to create a class name binding in Vue + JSX?
You would just bind to the class attribute like you would any other attribute:
<div class={this.klass}>
data() {
return {
klass: 'foo'
}
}
The lack of documentation, plus the wording on the guide gives the impression JSX is not the "proper" way to write Vue components. Is that so? What's the idiomatic way to do it, given I don't want to ship the compiler along with my app?
JSX is definitely supported, but it is not the recommended approach. The recommended approach is to write *.vue files and load them with vue-loader (if using Webpack).
Vue comes in two versions, one with and one without the template compiler. The one with the compiler included is only for development and should not be used for production builds (unless you require string template to render function compilation at runtime, which is unlikely). See Explanation of Build Files for more info.
Typically you write HTML string templates, and they get compiled to render functions (by vue-loader) at build time.

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.

Compile string with custom elements

I have an Aurelia application in which I'm trying to build a CMS component. This component will load data from the server and this data mainly contains slug, title and content fields.
I also have several global components defined in my application, and I want to be able to use those components in the server so when I pull that data my CMS component is able to transform/compile those custom elements.
An example would be a tab component. I have the tab component with this structure defined:
<tab-panel>
<tab title="First"></tab>
<tab title="Second"></tab>
</tab-panel>
The CMS component will contain a content property which I use to pass a string like this: '<tab-panel><tab title="First"></tab><tab title="Second"></tab></tab-panel>'
The component needs to compile that string and render it in its view. I've checked the enhance API, but it doesn't worked, at least for me. Any other suggestion to dynamically compile/render custom elements??
Thanks a lot in advance.
I've found the solution. I've used a compose element and InlineViewStrategy and it worked well, the components are shows and binding works as expected.
If your custom elements are registered globally using globalResources you can actually using the TemplatingEngine to dynamically insert content into the DOM and then compile it after-the-fact. This blog post goes into detail in how you can do it.
However, I would use this as a last resort. As is mostly always the case, there are much better ways to do something in Aurelia. Using the <compose> element is a great way to dynamically render content in your Aurelia applications and should always be the first port of call.

Default EditorTemplates

I'm trying to just ever so slightly tweak the default EditorTemplate for a SelectList. Is there somewhere where I can find the source for all the default EditorTemplates (i.e so I have a base reference to work off of).
I've had a peek on the asp.net mvc source page and cannot find the templates listed in their source code (although I am most likely missing it).
The default EditorTemplate for a SelectList is actually just this method:
System.Web.Mvc.Html.SelectExtensions.SelectInternal()
So it is not implemented as a .cshtml template at all. Instead it builds up the markup in C# using a TagBuilder. You could take this implementation as a starting point for your own C# method, or else port it into the equivalent razor syntax.