I have simple bootstrap(3) tabs inside a div (class="example").
I have the div saved in a Partial view.
I am using foreach loop in my Razor view, passing the object to the Partial view and outputting it for each iteration.
How can I simply navigate each div's own tabs without affecting other tabs inside the loop?
View:-
#foreach (var pbrModel in Model)
{
#Html.Partial("~/_TestViewPartial.cshtml", pbrModel)
}
Partial View:-
#model PbrViewModel
<div class="example">
<!-- Nav tabs -->
<ul class="nav nav-tabs">
<li class="active">Home</li>
<li>Profile</li>
<li>Messages</li>
<li>Settings</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="home">...</div>
<div class="tab-pane" id="profile">...</div>
<div class="tab-pane" id="messages">...</div>
<div class="tab-pane" id="settings">...</div>
</div>
</div>
You can use a for loop to iterate over the items in your main view's Model, and then use the i iterator to make each tab's id unique by appending it in the partial view.
You can pass the i value as a "model" to the partial view when you iterate.
Like so:
#for (var i = 0; i < Model.Count; i++)
{
#Html.Partial("~/_TestViewPartial.cshtml", i)
}
Then in the partial view, you can use the "model" passed to it from your for loop - in this case as an int type, so it can print the value into the ids accordingly.
Like so:
#model int
<div class="example">
<!-- Nav tabs -->
<ul class="nav nav-tabs">
<li class="active">Home</li>
<li>Profile</li>
<li>Messages</li>
<li>Settings</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="home#Model">...</div>
<div class="tab-pane" id="profile#Model">...</div>
<div class="tab-pane" id="messages#Model">...</div>
<div class="tab-pane" id="settings#Model">...</div>
</div>
</div>
Much like my previous (before this edit) answer, passing the i variable to each iteration ensures the ids are unique.
Unfortunately, with this way you will not be able to access any properties of the main view's Model, as you are only passing the int to the Partial view, and nothing else (I explain more below).
A couple of notes to think about:
Your path to the partial doesn't need to be "relatively absolute". In that, I mean you can just use "_TestViewPartial.cshtml" as the first argument (omitting the "~/")
If you do wish to access properties of your main view's pbrModels inside the partial, you will need to pass these to the partial (as per your OP, with PbrViewModel as the #model type) and I would suggest adding a unique indexer property to that type, if possible - so you can then print this in the id/href of the elements within your partial view, like in my example; just use #model.MyUniqueIDProperty or whatever friendly name you have for it
THINK - Do you really need a separate partial view for this? If you're reusing the code elsewhere, then yes. If it's solely for the purpose of the page, then no; I would defer to having the code in the main view's code - you would then still be able to access the main Model of the page, if you need to get properties from the PbrViewModels using the indexer you're at (Model[i])
Any questions, just ask.
Hope this helps! :)
Related
I'm sending 'SSR data' to my react component ()
The problem is;
Generallayout returns
<header className={`topbar-shadow`}>
<div className="header-top">
<div className="promo-message">
Some text over there
</div>
</div>
<div className={`header-bottom`}>
<div className="container">
<ul className="main-menu">
{headerData.map((item, index) => (
<li class="items">Item 1</li>
....blablabla
headerData is 'SSR data' that I passed throught component like <GeneralLayout headerData={headerData} />
When I load my website,
website returns firstly <li class="items">Item 1</li> before render <header>. So that, CSS is broken because It's not wrapped by header.
Whats wrong with it?
Why my whole header renders at the same time? What should I do for render this inside the header whole time?
I implemented the UIkit sortable component and added a stop event. But I can't figure out how to calculate the new order if an item has been dragged. So far the only thing I can think of is giving each item an id then calculating based upon that id, but it doesn't seem like the proper way to do so
There is a quite simple way of achieving this. The element stores originalEvent where you can find also explicitOriginalTarget - our moved element. As it is wrapped in li inside ul, I went up to its parentNode (li), so I am at the level of elements I need, then converted it to jQuery object (you don't have to, I did it just because it was quick), then you can get its index. All of these values can be accessed by console.log(e);
Only problem with this solution is performance, it works, but when you move elements too often, it can show 0 instead of correct index value
EDIT: I realized you're probably asking about the whole set of items and their order, not only the index of currently moved item, so I added also console logging for this as well
Example below:
var indexes = new Array();
$(document).on('moved', '.uk-sortable', function(e) {
var currentLi = e.originalEvent.explicitOriginalTarget.parentNode;
indexes = [];
$(this).find('li').each(function() {
indexes.push($(this).data("index"));
});
alert("New position: " + $(currentLi).index());
console.log(indexes);
});
$('.uk-sortable').find('li').each(function(i) {
$(this).data("index", i);
indexes.push(i);
});
console.log(indexes);
<!-- UIkit CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/css/uikit.min.css" />
<!-- UIkit JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit-icons.min.js"></script>
<ul class="uk-grid-small uk-child-width-1-4 uk-text-center" uk-sortable="handle: .uk-card" uk-grid>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 1</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 2</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 3</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 4</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 5</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 6</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 7</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body">Item 8</div>
</li>
</ul>
I came across this searching for something else and happen to know the answer you're looking for. You don't need jQuery or anything else for this, just UIkit.
<ul id="sortable-element" uk-sortable>
<li class="uk-sortable-item" data-id="1">Content</li>
<li class="uk-sortable-item" data-id="2">Content</li>
<li class="uk-sortable-item" data-id="3">Content</li>
<li class="uk-sortable-item" data-id="4">Content</li>
<li class="uk-sortable-item" data-id="5">Content</li>
</ul>
let sortable = UIkit.sortable("#sortable-element");
UIkit.util.on(sortable.$el, "added moved", function(e, sortable) {
sortable.items.forEach(function(item, index) {
console.log({ item, index});
// Grab data attributes if you need to.
// UIkit.util.data(item, "id");
});
});
The second parameter of the callback references the sortable component and contains the array of item elements. Loop through this array and use the index (0 based) to get the new order of items. It's important to use the .uk-sortable-item or define a different class with the cls-item option for the sortable component to return the items.
You also don't need to define sortable like I have, you can just use the UIkit.util.on with CSS selectors, e.g. UIkit.util.on("#sortable-element", "added moved removed start stop", function(e, sortable) { console.log(e.type); });
UIkit.util is more or less undocumented, but it's extremely well built. Check the repo to see available functions. They are binded to UIkit.util in the dist/uikit.js file. https://github.com/uikit/uikit/tree/develop/src/js/util
The easiest way I have found is to get the list of all the elements and perform a mapping operation that returns an array of unique & identifiable attributes (e.g. the IDs of the sortable elements.
The moved event has a detail property that's an array containing the UIKitComponent and the target element; you can get the items from the UIKitComponent.
const new_order = event.detail[0].items.map(el => el.id);
//["id-1", "id-2", "id-3"];
You can then get the indices after the fact, at least the messy DOM side of things is sorted.
Here is how my structure is setup:
I have many Services (DocType) which hold children Documents (DocType).
The Document DocType can have other Document elements as its children.
This way, it's possible for editors to create that kind of tree:
Service > Document> Document >Document > Document
There's no limits to the amount of levels this can go on for.
I'm trying to find a way to loop recursively through each Document and their descendants, but they need to be nested within eachother. This is where I'm having trouble.
I can't seem to find a simple way to loop recursively through each levels per children to generate the content.
Here is what I have so far:
#{ var selection = Model.Children.Where("Visible");
if (selection.Any()) {
<ul>
#foreach (var item in selection) {
<li>
<div class="ServiceDocCenterDocumentation">
<h4>#item.Name</h4>
<div class="DocCenterDocumentationDescription">#item.GetPropertyValue("bodyText")</div>
</div>
<div>
#foreach (var children in item.Descendants()){
#* This is the part I'm struggling with for the last few days *#
var actualChildren = children;
<h5>#children.Name</h5>
<div class="DocCenterDocumentationDescription">#children.GetPropertyValue("bodyText")</div>
}
</div>
</li>
}
</ul>
}
}
Here's what I would like to achieve (recursively, not manually):
<div class="myService">
<div class="Documents">
<div class="Document_#elem.Id">
#elem.bodyText
foreach (var child in elem.Children){
<div class="Document_#child.Id">
#child.bodyText
foreach (var grandchild in child.Children){
#* It goes on and on for the amount of levels available *#
}
</div>
}
</div>
</div>
</div>
I'm still not very fluent in Razor, and I'm wondering if there's a way of achieving what I would like to achieve.
You should use Razor helpers to create your recursive function.
Apart of that, you shouldn't use Descendants in each children as it would return every node below this one. You just need its children, then the children of each children and so forth. So you will pass each children list to the function to display it.
#{ var selection = Model.Children.Where("Visible");
if (selection.Any()) {
<section class="DocCenter">
#foreach (var item in selection) {
<section class="Service">
<div class="ServiceDocCenterDocumentation">
<h1>#item.Name</h1>
<div class="DocCenterDocumentationDescription">#item.GetPropertyValue("bodyText")</div>
</div>
#DisplayChildren(item.Children().Where("Visible"))
</section>
}
</section>
}
}
#helper DisplayChildren(IEnumerable<IPublishedContent> children){
if(children.Any()){
<section class="children">
foreach(var child in children){
<section class="Document_#child.Id">
<div class="DocumentDetails">
<h1>#children.Name</h1>
<div class="DocCenterDocumentationDescription">#children.GetPropertyValue("bodyText")</div>
</div>
//Recursive call here
#DisplayChildren(child.Children().Where("Visible"))
</section>
}
</section>
}
}
On the other hand, although is not related to the recursive question, I would use the <section> element to separate parents and children, that way you can also use h1 for all the headings as they are created in a section hierarchy:
Using HTML sections and outlines
Let's say I created a menu titled "Main Menu" from the admin panel and I need to customize the default markup, e.g. let's say I want to modify/replace the <ul>, <li> as well as the surrounding <article> and <nav> tags.
I assume that I have to come up with something like this in my Parts.MenuWidget.cshtml alternate template.
<ul class="a b c">
for each item in menuItems:
display("<li>" + item + "</li>")
end
</ul>
How do I do that in Orchard?
That's quite simple.
You could first create an alternate for you MenuWidget like so:
Parts.MenuWidget-MyZoneName.cshtml
<nav>
<div class="logo">
#Html.Partial("_Logo")
</div>
<ul>
#*Display all the stuff added in the admin*#
#DisplayChildren(Model.Menu)
#*Add additional stuff. Of course you could also add it as MenuItem to the Menu-Model*#
#if ( Request.IsAuthenticated )
{
if ( Authorizer.Authorize(StandardPermissions.AccessAdminPanel) )
{
<li>
<a href="/Admin">
Admin
</a>
</li>
}
<li>
<a href="~/Example1">
Extra1
</a>
</li>
}
else
{
<li>
<a href="~/Example2">
Extra2
</a>
</li>
}
</ul>
</nav>
And then go on and do something similar for your MenuItems. For example:
MenuItemLink.cshtml
#Model.Text
Another thing that's worth mentioning is that you can either only provide an alternate for a specific shape like the MenuItemLink above or just provide an alternate for the base MenuItem shape which will then be used for every MenuItem type that exists.
(Maybe those are not the best examples, but I guess they'll do the job ;) )
Update:
In order to remove/modify the tags you can create an alternate for MenuItem.cshtml and look at this part:
if (HasText(renderedMenuItemLink))
{
var tag = Tag(Model, "li");
#tag.StartElement
#renderedMenuItemLink
if (items.Any())
{
<ul>
#DisplayChildren(Model)
</ul>
}
#tag.EndElement
}
Ok I saw many posts on how to serialize the value of dragged items to get hash and they tell how to save them. Now the question is how do I persist the dragged items the next time when user log's in using the has value that I got
eg:
<ul class="list">
<li id="id_1">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_2">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_3">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_4">
<div class="item ui-corner-all ui-widget">
</div>
</li>
</ul>
which on serialize will give
"id[]=1&id[]=2&id[]=3&id[]=4"
Now think that I saved it to Sql server database in a single field called SortOrder.
Now how do I get the items to these order again ?
the code to make these sort is below, without which people didn't know which library I had used to sort and serialize
<script type="text/javascript">
$(document).ready(function() {
$(".list li").css("cursor", "move");
$(".list").sortable();
});
</script>
There are a few options. One option is to do the sorting server-side. You would read out that string in .NET to generate the list, in order, on the fly. Then output it to the browser.
Another option would be output the serialized string as a string variable in javascript. You could then use jQuery to reorder the elements. The problem with this method is that there would probably be a flash where the unordered list would display and then the correctly ordered list would appear.