Pass (or inject) some HTML/JS or pass some model to shared Net Core Razor Class Library - asp.net-core

I would like to have a shared UI project with common interface for other apps, so I don't have to copy/paste the same _Layout.cshtml between all apps which need same UI.
After using this question as reference and this article I have created shared Razor Class Library project. And when I reference this project via NuGet, the _Layout.cshtml in this shared project gets called and renders header with navigation.
But my problem comes then if I want to add some extra HTML to header. Let say I have drop down with some link to main landing page, to user setting, some administration page and etc. But how could I add some extra navigation links specific to concrete app next to all common links? Is there a way to inject HTML? Or maybe to pass some DTO model to this _Layout.cshtml?
Dump image below to help you to see what I try to achieve.

There's two possible approaches. First, you can simply call a partial in your layout:
<partial name="_HeaderExtra" />
Then, just add an empty partial view to the RCL, so it's satisfied, i.e. _HeaderExtra.cshtml. Finally, in your actual application, create the same partial view in the same location as the one in the RCL, and add whatever extra HTML you want there. When the partial is pulled into your layout, it will looking your project first, before falling back to the RCL.
The second option is to use sections. Sections are a little bit more strict, and you must remember to always reimplement them if you do any view inheritance. Essentially, in your layout, at something like:
#await RenderSectionAsync("HeaderExtra", required: false)
Then, in any sublayouts or views:
#section HeaderExtra
{
<!-- add something here -->
}
If you've got a sublayout and you want to be able to further customize this section in views, then you need:
#section HeaderExtra
{
#await RenderSectionAsync("HeaderExtra", required: false)
<!-- add something here -->
}

Related

Nuxt layout and getting static content

I have a header on every page thats generally static — besides the button that needs to update based on the page. Ideally I would like to have a variable called link in static/content/xxx
and then to call it from layouts/default. However it does not seem that I have access to any of the variables in my static content. Being new to vue and nuxt I was hoping for some guidance. I tried using asyncData however, it doesn't seem to get called at all in my layout.
a layout is a static wrapper that will wrap your main content. the main idea behind using layout is to not write the same content again and again. If you work with Vue only project than this type of functionality can be accessed by the using the child routes.
just add the common layout as the parent Component and the changed or different content as the child components.
back to the point, if you have different button content depending upon the pages than don't place it in the layout instead pass through the components individually.
whereas the static folder in the nuxt application holds the data that should not be changed such as the css files or external script files just take and example of bootstrap and jquery these are the libraries that are embeded in the application, instead of changing their internals we just use them. this type of content is placed in static directory (folder)
I hope it helps

Aurelia - dynamically create custom element in a view-model

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.

Can PartialViews replace with TagHelpers in ASP.NET Core?

I am new to ASP.NET Core. I just discovered TagHelpers and as I may get the idea, theoretically we should be able to replace partial views with tag helpers.
Beyond that, TagHelper can accept input but PartialView don't.
do I think right? or it's a misunderstanding? can anyone explain the difference clearly?
Thanks in advance!
This is for asp.net core 2.1+
If I understand your question correctly, you can replace all your HtmlHelper partial views with your own TagHelpers, but you were already able to do this with HtmlHelpers so its not something new.
However, there is a difference between HtmlHelpers, TagHelpers and Partial Views.
Partial Views
A partial view is a Razor markup file (.cshtml) that renders HTML output within another markup file's rendered output. Eg _partial.cshtml.
HtmlHelper
HtmlHelpers were introduced with the MVC framework to be able to render html serverside. Easily distinguished by the # character in razor views.
#await Html.PartialAsync("_partial.cshtml", Model.Contact)
Beyond that, TagHelper can accept input but PartialView don't.
The second parameter in PartialAsync allows for input.
TagHelper
With asp.net-core, TagHelpers are another way to be able to render server side html by using tags and attributes in the razor views. Aside from html friendly views, it provides less abstraction from html. In the code below I'm using the Partial TagHelper, where the name attribute defines the path or name of the view, and the for attribute assigns the model expression that will evaluated (#Model). This means you don't need to use for="#Model.Contact" and simply just for="Contact".
<partial name="_partial" for="Contact" />
You could also use the model attribute, which just passes the model to the partial view on instantiation.
<partial name="_partial" model='new Contact { Id = 1, Name = "Nick" }' />
As seen from above, both TagHelpers and HtmlHelpers can render partial views.
Furthermore if you look at asp.net-core github for the HtmlHelper
https://github.com/aspnet/Mvc/blob/b18526cdc8d8c868e8d7f9c6c8484064215e1002/src/Microsoft.AspNetCore.Mvc.ViewFeatures/HtmlHelper.cs#L554
and compare it to the TagHelper
https://github.com/aspnet/Mvc/blob/b18526cdc8d8c868e8d7f9c6c8484064215e1002/src/Microsoft.AspNetCore.Mvc.TagHelpers/PartialTagHelper.cs#L216
Both are actually calling and IView.RenderAsync() and passing in a ViewContext which includes the partial view. So they virtually do the same thing in code behind, except for the way it manipulates the html.
Side notes:
Much like HtmlHelpers, you can also create your own TagHelpers which can replace whole partial views.
TagHelpers are not to replace HtmlHelpers, but provide alternative approach. However, in my opinion TagHelpers are better. They render better in visual studio editor (razor pages used have a lot of formatting problems due to the #HtmlHelpers), is way more readable, and comply with html.
In the partial TagHelper, you can use either model or for to provide data to the partial, but never both.
Omitting .cshtml from the name will just force the framework to search for the view in Pages, Views, and Shared folders. Its totally optional.
Hope this helps

Using Big Commerce Product Custom Fields in Templates

I have come to a road block in my search to the answer to using custom fields in templates.
I have tried adding
%%SNIPPET_ProductCustomFields%%
in the ProductDescription.html but nothing shows.
Is there ANY documentation about this?
Can this snippet be used in certain places only? if so which ones?
What needs to be in place for this to display in the products description?
Any help, tips or pointers would be great.
The CustomFields Snippet, %%SNIPPET_ProductCustomFields%%, can only be used if being referenced through its own Panel.
By default, the Panel that calls this snippet is named %%Panel.ProductOtherDetails%%
You can also create your own custom Panels by uploading them to the Panels folder via WebDav.
For example, if you created a template file called CustomFieldsPanel.html, you would upload it to the /dav/template/Panels folder, and reference it in your theme by %%Panel.CustomFieldsPanel%%
To answer your question though, you can do one of the following to display Custom Fields in the Product Description:
Insert it into ProductDescription.html via its default Panel - %%Panel.ProductOtherDetails%% - modifying it by editing the template file ProductOtherDetails.html
Create your own custom panel, include the Snippet within that same custom panel, and insert it into ProductDescription.html by the custom panel's name. An example of that file might look like so:
<!--
* /dav/template/Panels/MyCustomFieldsPanel.html
* %%Panel.MyCustomFieldsPanel%%
-->
<div id="MyCustomFieldsPanel">
<h1> Custom Fields Below </h1>
%%SNIPPET_ProductCustomFields%%
</div>
Hope this helps :-)

How can I embed a twitter timeline in a Durandal view?

The code to embed the widget is nice and simple, but it includes javascript in tags.
Durandal appears to strip out such script tags.
How do I use the embed code in a Durandal view?
https://dev.twitter.com/web/embedded-timelines
<a class="twitter-timeline" href="https://twitter.com/XXX" data-widget-id="XXX">Tweets by #XXX</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
You would need to write a custom Knockout binding, or create a Durandal widget where the view is your tag, and the viewModel handles the JavaScript in your tag.
Some notes: In your widget's view model, you would avoid d.getElementsByTagName(s) in favor of simply referencing the view reference passed in to either the attached or compositionComplete handler that Durandal provides. In fact, you could pretty much eschew all direct DOM manipulation in favor of Durandal's imported view references and Knockout's/Durandal's templating/composition.
UPDATE
Take a look at this from the documentation you reference: "If you’re already including our ‘widgets.js’ JavaScript in your page to show embedded Tweets or Twitter buttons, you don’t need to include this script again; it updates automatically to support new features."
This could lead you down the path of simply referencing widgets.js in a script tag in your index.html or index.chtml file.
You cannot use script tags in Durandal views, but you can use them in your index page.
SECOND UPDATE
Once widget.js has been referenced in a script tag in the index.html or index.chtml (or perhaps even by using AMD), it becomes a matter of choosing the proper Durandal point at which to load the Twitter widget. This could be either in the attached handler or in the compositionComplete handler, as indicated above.
As the OP pointed out in his comments, a functional place to do this is compositionComplete, in the following manner:
var compositionComplete = function () {
twttr.widgets.load();
}
as documented here.
This assumes that twttr is either on the window or injected into the viewModel.
POSSIBLE MEMORY LEAK
It is equally important to note that unloading of widgets must take place in the Durandal's detached handler. Use Twitter's API to unload, and then be sure to nullify the windows reference.