I'm looking for a way to dynamically provide at runtime view models for any views. Question is if there is hook in the ViewEngine or a view model loader / factory that I can use to do this.
I'm looking into bridging into WebAssembly and allowing view models to be written in other languages and I want to create automatic interop view models on the Javascript side for Aurelia to just work.
This is totally doable, and many have successfully delivered their ultra-dynamic application using Aurelia, as pretty much everything in Aurelia is dynamic.
For example:
dynamic, instance based inline view: https://codesandbox.io/s/r0no20706p (Based on this discourse topic https://discourse.aurelia.io/t/template-literals-in-class-instance/1829/6)
dynamic, remote view strategy: https://codesandbox.io/s/8ljmrq3vql (Based on a github question)
dynamic, route based view model: https://codesandbox.io/s/ywyj60p9qj (based on this discourse https://discourse.aurelia.io/t/ideas-on-data-driven-ui-composition-vs-previous-angularjs-approach/2269/3
Basically it boils down to is to use .compose method from CompositionEngine:
compositionEngine.compose({
viewModel:
string // as module path
| Function // as constructor
| object // as instance
})
And make sure the view is resolvable from the view model.
Related
I have an Aurelia app where a user can click on a button and create a new tab. The tab and its content (a custom element) do not exist on the page before the user clicks the button. I am generating the HTML for the content at runtime (via Javascript) in my view model.
I keep seeing mention of using the template engine's compose or enhance functions, but neither are working for me. I don't know how I would use the <compose> element (in my HTML) since I am creating the element based on the user clicking a button.
My thought was that the button has a click.delegate to a function that does ultimately does something like
const customElement = document.createElement('custom-element');
parentElement.appendChild(customElement);
const view = this.templatingEngine.enhance({
element : customElement,
container : this.container, // injected
resources : this.viewResources, // injected
bindingContext: {
attrOne: this.foo,
attrTwo: this.bar,
}
});
view.attached();
But all this does is create an HTML element <custom-element></custom-element> without actually binding any attributes to it.
How can I create a custom element analogous to <custom-element attr-one.bind="foo" attr-two.bind="bar"></custom-element> but via Javascript?
As you pointed out in your own answer, it's the missing resources that caused the issue. One solution is to register it globally. That is not always the desired behavior though, as sometimes you want to lazily load the resources and enhance some lazy piece of HTML. Enhance API accepts an option for the resources that you want to compile the view with. So you can do this:
.enhance({
resources: new ViewResources(myGlobalResources) // alter the view resources here
})
for the view resources, if you want to get it from a particular custom element, you can hook into the created lifecycle and get it, or you can inject the container and retrieve it via container.get(ViewResources)
I found the problem =\ I had to make my custom element a global resource.
Trying to implement the layout of the picture below, I would like to ask about best practices regarding the architecture of the page layout. Is it better to have independent ViewComponents in every section of the page or partial views? Is it possible to have nested ViewComponents?
The idea is to reuse the sections in other positions in different pages. The concept is very similar to Web parts we used to have but now I try to implement something like this with Asp. Net Core.
Yes, it is possible to have nested View Components.
What is important to keep in mind:
You should keep your views structure under Components folder plain
You should keep your ViewComponent classes under ViewComponent folder plain
You should control infinite loops yourself when you nest component1 into component2 and at the same time component2 into component1
NOTE: most likely you will need your components to include edit/save/update functionalities. As far as I understand, View Components are supposed to be views only as they have only InvokeAsync and not something like UpdateAsync. So if you'd like to implement any kind of saving logic, you will need to take care of doing this yourself (e.g. via AJAX calls). It is possible (I have verified), but it requires to get familiar with Microsoft.jQuery.Unobtrusive.Ajax and handle responses on the client side in JavaScript (sometimes including things like replacing in JS the DOM element inner HTML with what you get from the server response). You will also need to decide where to put controller actions for view component update endpoints (could be a special Controller class for View Components).
I started to use GWTP for my project and I'm currently re-writing all my code to let it work with this library.
However, I struggle to understand how I use GWTP if I want e.g. a ListView with ListItemView items.
#Inject
public ToolsPresenter(PlaceManager placeManager, EventBus eventBus, MyView view, MyProxy proxy) {
super(eventBus, view, proxy, AdminToolPresenter.SLOT_AdminToolMainContent);
this.placeManager = placeManager;
ToolListView toolListView = new ToolListView(...)
ToolListPresenter toolListPresenter = new ToolListPresenter(....);
this.setInSlot(SLOT_ToolList, toolListPresenter);
}
What I want is to place my ListView inside a slot. I am very certain that I can't do what is shown up there but I just don't get how I use just simple Widgets with GWTP.
Or am I doing this completely wrong and I should just extend a Composite for ListView and not use GWTP stuff here at all?
There is a lot of information missing from your question so this is a difficult one to answer.
Assumption 1 - Your GWTP artifacts (ToolListView, ToolListPresenter, ToolListView.ui.xml, and ToolListModule) are setup correctly and ToolListModule is installed in a parent module.
Assumption 2 - You are using GWTP version 1.5+ which has typed slots.
You should not be instantiating your ToolListView or ToolListPresenter.
Simply add:
#Inject ToolListPresenter toolListPresenter;
If you are trying to call the setInSlot method then
Make sure ToolListPresenter is a PresenterWidget
Make sure your slot is not a NestedSlot.
Finally try moving the call to setInSlot outside of your constructor and into the overridden onBind() method.
I have an elm app designed with the Elm Architecture in mind. I've used it for all the samples in the tutorial and they work fine. I have the following components
ContainerListView
ContainerView
AddressView
RegistrationView
...
The ContainerView component is a very formatted div structure that is used to contain other views (but for now, only 1 at a time)
ContainerListView can contain multiple containerViews. It handles their presentation and positioning. You can think of it as an MDI surface
A menu from the main ui is used to add new container views to the container view list.
I'm presented with with three main questions. Two of them are
How do I create the components such that Container view can contain any other element is I pass in for example the init, update, and view functions and expect all things to be wired correctly? At the moment, the samle views I have are kinda hard-coded. They know exactly who the children is.
Some of the components require access to things like url, access token, etc. Does this always have to be passed in from main to the individual components or it can come from another source which will essentially be readonly and maybe updatable only from main?
I'm not sure if these two should be individual questions on their own. Any information on how to architect larger apps beyound hello world will also be appreciated.
I'm working on something similar! Nested controls. I too have a container object which knows about all the types that it can handle, and has basically case statements to handle each type. So I can't drop in a new control type and expect it to handle it, that requires altering the container.
As far as I know elm doesn't have type classes, which would be how I might try to handle that kind of abstraction in haskell or purescript. There's more about that here:
https://github.com/elm-lang/elm-compiler/issues/38
and here:
https://github.com/elm-lang/elm-compiler/issues/1039
The upshot appears to be that they don't know how they want to solve that problem yet, so they haven't.
I'm trying to understand the use case differences between TagHelpers and ViewComponents in asp.net 5 because the end result functionality seems very similar. We have TagHelpers that can create new HTML tags that get parsed by the Razor engine and then ViewComponents that get explicitly invoked. Both return some HTML content, both are backed by their respective base classes, both have async versions of methods they can implement to get their work done.
So when would one be used over another? Or am I missing some information?
There's definitely some conceptual overlap between TagHelpers and ViewComponents. TagHelpers are your utility to work with HTML where ViewComponents are your way to stick to C#, do isolated work and then spit out HTML. I'll go into each in detail:
ViewComponents
Your conceptually equivalent mini-controller; you will see that many of the methods/properties that ViewComponents expose are very familiar to those that exist on a Controller. Now as for invoking ViewComponents, that's more equivalent to utilizing HTML helpers (one thing TagHelpers make better). To sum up ViewComponents: Their primary purpose is to feel like a controller, stay in C# land (there may be no need to add utility to HTML), do smaller/isolated work and then spit out stringified HTML.
TagHelpers
A utility that enables you to work along side existing HTML or create new HTML elements that modify what happens on a page. Unlike ViewComponents TagHelpers can target any existing HTML and modify its behavior; example: you could add a conditional attribute to all HTML elements that would conditionally render the element server side. TagHelpers also allow you to intermingle common HTML terms, ex:
<myTagHelper class="btn">Some Content</myTagHElper>
As you can see we're adding a class attribute to our TagHelper just as if it were HTML. To do this in ViewComponents, you'd need to pass in a dictionary of attributes or something equivalent (unnatural). Lastly multiple TagHelpers can run over a single HTML element; each having their own stage at modifying output (allows entry for modular TagHelper toolkits). To sum TagHelpers up: They can do anything that ViewComponents can do and more BUT do not feel familiar to things like Controllers that ASP.NET developers are used to; also some projects may not want to intermingle server side HTML.
Extra:
I recently did a video showcasing the benefits of TagHelpers. Basically a walk through of what they're good at and how to use them. You can watch it here.
When deciding which one to use I always consider how complex the HTML of the component will be.
If it's something simple like a tree view or a pager
<ul class="jstree">
<li>Node 1</li>
<li>...</li>
</ul>
That is candidate for tag helper, because it's simple. Large HTML in a C# code would be hard to maintain.
On the other hand if it's complex HTML with many divs, images and configuration like a full blown menu where it can be vertical or horizontal that's your view component. Benefit of view component is that you can use multiple views so for menu so you can separate horizontal.cshtml & vertical.cshtml while reusing same backend code.
Turns out that in .Net Core 1.1, you can call a ViewComponent using the tagHelper syntax.
Regarding Taylor's comment "Their primary purpose is to feel like a controller", it is true, but since you cannot directly call this "micro-controller" directly, the "controller-like" behavior is limited in that you can only create a part of a page, you cannot call it again (say via an ajax call, an Edit Action, etc).
One primary difference between TagHelpers and ViewComponents relates to how much work needs to be done by the object. TagHelpers are fairly basic, requiring only a single class that overrides the Process method to produce the output of the TagHelper. The downside is that if you do any complex work to create inner HTML in the TagHelper, it has to all be done in code. In a ViewComponent, you have a mini-controller capable of doing a lot more work, plus it returns a view, where you have actual Razor syntax code that can be mapped to a model.
Another post mentioned that ViewComponents are more "HTML Helper"-y in how you call them. ASP.NET 1.1 addressed that issue, so that you can call it with
<vc:view-component-name param1="value1" param2="value2></vc:view-component-name>
For most purposes, a TagHelper has a definite advantage, because it's easier. But if you need a more robust solution, ViewComponent is the way to go.
And yet something that kind of defeats the purpose of View Components (IMHO) is that from the View Component class there seems to be no way to access the Inner Html of the VC if you use the tag helper syntax:
<vc:MyComponent id="1" att="something">
Some HTML markup you would not want to put in an attribute
</vc:MyComponent>
There are however good applications of a VC such as the Bootstrap Navigation Bar View Component I saw in a TechieJourney blog post.