Make .NET Core app reload experience like angular/react - c#

I have a website build with .net core technology.
there are menu on left side, and display content on right side.
but currently, when I click to menu, it reload entire page and load all menu again and then load content of page.
what I want is, when click on menu, it should load content for that menu without reloading page.
below code I tried, but I think that causes issue, because I used global variable in JavaScript in every page, so when I click on any menu that will call my below function and load content, but when I click on another menu it load another page, but first page global variable are still access on second page.
async function getPage(url) {
let response = await fetch(url);
let data = await response.text();
return data;
}
function loadPage(url) {
$("#main-layout-container").html("<div class='div-loader'></div>");
getPage(url).then((data) => {
$("#main-layout-container").html(data);
});
}

If you use JavaScript, I wrote a simple demo:
View:
<div class="all">
<div class="menu">
<ul class="first">
<li>
First-level directory-1
<ul class="sec">
<li>1-1</li>
</ul>
<div class="content">1-1:content</div>
</li>
<li>
First-level directory-2
<ul class="sec">
<li>2-1</li>
<li>2-2</li>
</ul>
<div class="content">2-1:content</div>
<div class="content">2-2:content
</div>
</li>
<li>
First-level directory-3
<ul class="sec">
<li>3-1</li>
<li>3-2</li>
<li>3-3</li>
</ul>
<div class="content">3-1:content</div>
<div class="content">3-2:content</div>
<div class="content">3-3:content</div>
</li>
<li>
First-level directory-4
<ul class="sec">
<li>4-1</li>
<li>4-2</li>
<li>4-3</li>
<li>4-4</li>
</ul>
<div class="content">4-1:content</div>
<div class="content">4-2:content</div>
<div class="content">4-3:content</div>
<div class="content">4-4:content</div>
</li>
</ul>
</div>
<div class="clear"></div>
</div>
#section Scripts{
<script src="~/jquery/jquery.js"></script>
<link href="~/css/test.css" rel="stylesheet" />
<script>
var firstList = $('.first > li'); // Grab the first level menu li
var secList = $('.sec'); // Grab the ul of the secondary menu for easy operation
secList.hide();
for (var i = 0; i < secList.length; i++) {
firstList.eq(i).children('.content').hide();
}
firstList.eq(0).children('.content').eq(0).show(); //The content below 1.1 is displayed by default
var ind = 0; // Define variables to store the subscript of the first-level menu when clicked
// Click event of the first level menu
firstList.click(function () {
ind = $(this).index();
if (secList.eq(ind).hasClass('show')) {
for (var j = 0; j < secList.length; j++) {
secList.eq(j).hide();
}
secList.eq(ind).removeClass('show');
} else {
for (var k = 0; k < secList.length; k++) {
secList.eq(k).hide().removeClass('show');
}
secList.eq(ind).show();
secList.eq(ind).addClass('show');
}
});
// Click event of secondary menu
$('.sec > li').click(function (event) {
var sec = $(this).index();
for (var i = 0; i < secList.length; i++) {
firstList.eq(i).children('.content').hide();
}
firstList.eq(ind).children('.content').eq(sec).show();
event.stopPropagation(); // Prevent events from bubbling up
});
</script>
}
Demonstration effect:

Related

ASP.NET Hide/disable entire dropdown menu based on user role

I have a drop-down list in an ASP.NET webform application generated in the sitemaster menu using the follow ing code:
<li class="dropdown" id="Admin" > <a class="dropdown-toggle" data-toggle="dropdown" href="#">Admin<span class="caret" ></span></a>
<ul class="dropdown-menu" >
<li><a runat="server" href="~/Admin/Members">Members Management</a></li>
<li ><a runat="server" href="~/Admin/MembersRegistry">Members Registry</a></li>
</ul>
</li>
and the script to generate the drop down is
<script>
$(document).ready(function () {
$(".dropdown").hover(function () {
//toggle the open class (on/off)
$(this).toggleClass("open");
});
})
</script>
I want to be able to hide or show the entire dropdown menu based on user roles:
protected void Page_Load(object sender, EventArgs e)
{
Admin.Visible = false;
if (System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>();
var user = HttpContext.Current.User.Identity.GetUserId();
if (manager.IsInRole(user, "Admin"))
{
Admin.Visible = true;
}
}
}
But this is not working and the Admin control is not accessible from the code behind, any thoughts or suggestions please?
If you add a runat="server" tag to that, then your code behind should see/have use of that controls, and you code looks like it should work ok.
eg:
<li class="dropdown" id="Admin" runat="server">
.etc. etc.
</li>

show a div of image only in homepage and hide from other pages

<div class="container">
#section HeroSection{
#foreach (var category in Model.AllCategory.Where(m => m.IsFeatured).FirstOrDefault().CategoryPictures.Select(m => m.Picture).Distinct())
{
<div class="hero__item set-bg" data-setbg="/FileStore/images/#category.Url">
<div class="hero__text">
<span>FRUIT FRESH</span>
<h2>Vegetable <br />100% Organic</h2>
<p>Free Pickup and Delivery Available</p>
SHOP NOW
</div>
</div>
}
}
</div>
</div>
</div>
}
</div>
I tried to #Render the //#section HeroSection// as false in _layout page .so that it will only appear in home/index ..not in other pages!
I can think of 2 approaches.
the first one is not so practical which is making 2 different layouts, one without the div and one with it. And you can change the layout of the homepage in the razor file like this
#{Layout = "YourNewLayOut"}
The other approach which I think it's better is to use JavaScript.
you can use window.location.href to get the current url and check if it's the url of the home page you target the div and make hidden otherwise visible.
your function should look like this :
function someFunctionName() {
let div = document.querySelector("#yourDiv");
if (window.location.href === "your home page url ") {
div.style.display = "none";
} else {
div.style.display = "block or flex or what ever you're using";
}
}
and then Invoke this function on loading like this
window.onload = function() {
someFunctionName();
};

.NET MVC Core handling form inside for loop with jquery/ajax - only returning first selection

I might be close, but can't seem to figure out what is missing in this case. I have a view that creates a form inside the questions for loop, and then the only field that has to be selected is from the radio button list generated by the answers for loop.
I am using jquery/ajax to post so that the page doesn't redirect on every submit. My code is working in that every time I click the saveLink button it creates a new record in the database. The problem is that when I select an answer for the first question, it saves the selectedquestionid and selectedanswerid of that question and answer, but when I move to the next question and select an answer, it saves the ids from the first question and answer again.
I need it to save the correct ids. Can anyone point me in the right direction?
View (simplified for brevity)
#for int(i = 0; i < Model.Questions.Count; i++)
{
<form asp-action="Save" id="myForm">
<div class="form-group">
#Html.HiddenFor(model => model.TestName)
#Html.HiddenFor(model => model.SelectedQuestionID, Model.Questions[i].ID)
#Html.DisplayFor(model => model.Questions[i].QuestionText)
#for (int j = 0; j < Model.Questions[i].Answers.Count; j++)
{
<div>
#Html.RadioButtonFor(model => model.SelectedAnswerID, Model.Questions[i].Answer[j].ID)#Html.Label("", Model.Questions[i].Answers[j].AnswerText)
</div>
}
</div>
<div class="form-group">
<input type="button" class="saveLink" value="Save" />
</div>
</form>
}
<script type="text/javascript">
$('.saveLink').click(function(e){
e.preventDefault;
$.ajax({
url:$(this).attr("href"),
type:'POST',
data:$('#myForm').serialize(),
success:function(){
alert("Saved");
}
});
});
</script>
Controller method
[HttpPost]
public void Save(RespVM respVM)
{
if (ModelState.IsValid)
{
var qid = _context.Answer.Where(a => a.ID == respVM.SelectedAnswerID).Select(a => a.QuestionID).FirstOrDefault();
var RespModel = new Resp
{
SelectedQuestionID = qid,
SelectedAnswerID = respVM.SelectedAnswerID,
TestName = respVM.TestName,
}
_context.Add(RespModel);
_context.SaveChanges();
}
When you do this:
$('#myForm').serialize(),
You serialize the 1st object with an id="myForm"
In your loop, you give all your forms the same id, so that's why it returns the 1st form everytime
<form asp-action="Save" id="myForm">
Instead of giving them and id, you should give them a class, and then refer to them from the clicked button. Something like that :
<form asp-action="Save" class="myForm">
$(this).closest('.myForm').serialize()

Umbraco pagination

First time Umbraco user.
I'm looking to add pagination to the following basic loop:
#foreach (var example in CurrentPage.Children.OrderBy("createDate descending").Take(8)){
//Do Stuff//
}
Any ideas? Thanks
After a good amount of work and research, here is my final code for pagination in umbraco. Replace the examples with your stuff, and pageSize is the amount of posts shown on each page.
#{
var pageSize = 8;
if(Model.Content.HasValue("numberOfItemsPerPage")){
pageSize = Model.Content.GetPropertyValue<int>("numberOfItemsPerPage");}
var page = 1; int.TryParse(Request.QueryString["page"], out page);
var items = Umbraco.TypedContent(Model.Content.Id).Children.Where(x => x.DocumentTypeAlias == "exampleAlias" && x.IsVisible());
var totalPages = (int)Math.Ceiling((double)items.Count() / (double)pageSize);
if (page > totalPages)
{
page = totalPages;
}
else if (page < 1)
{
page = 1;
}
foreach (var item in items.Skip((page - 1) * pageSize).Take(pageSize).OrderBy("createDate descending"))
{
<div class="example-div">
<h2>#item.GetPropertyValue("example")</h2>
</div>
}
if (totalPages > 1)
{
<div class="pagination">
<ul>
#if (page > 1)
{
<li>Prev</li>
}
#for (int p = 1; p < totalPages + 1; p++)
{
<li class="#(p == page ? "active" : string.Empty)">
#p
</li>
}
#if (page < totalPages)
{
<li>Next</li>
}
</ul>
</div>
}
}
Hope this stops a headache for someone.
Phil's answer is great, but I would recommend putting the order on the items variable rather than the foreach - that way if any more complicated sorting is necessary it's being done before the pagination is implemented.
The updated code snippets would be:
#{
var pageSize = 8;
if(Model.Content.HasValue("numberOfItemsPerPage")){
pageSize = Model.Content.GetPropertyValue<int>("numberOfItemsPerPage");}
var page = 1; int.TryParse(Request.QueryString["page"], out page);
var items = Umbraco.TypedContent(Model.Content.Id).Children.Where(x => x.DocumentTypeAlias == "exampleAlias" && x.IsVisible()).OrderByDescending(x => x.CreateDate);
var totalPages = (int)Math.Ceiling((double)items.Count() / (double)pageSize);
if (page > totalPages)
{
page = totalPages;
}
else if (page < 1)
{
page = 1;
}
foreach (var item in items.Skip((page - 1) * pageSize).Take(pageSize)
{
<div class="example-div">
<h2>#item.GetPropertyValue("example")</h2>
</div>
}
if (totalPages > 1)
{
<div class="pagination">
<ul>
#if (page > 1)
{
<li>Prev</li>
}
#for (int p = 1; p < totalPages + 1; p++)
{
<li class="#(p == page ? "active" : string.Empty)">
#p
</li>
}
#if (page < totalPages)
{
<li>Next</li>
}
</ul>
</div>
}
}
My 50 cents
Jeroen Breuer created a github project called Hybrid Framework in which he has added some route hijacking to an umbraco side to do paging and have strongly typed models. Take a look at it and i'm sure you will like it. It also uses caching i believe.
There was also a video about this i saw but i could not find it anymore.
Hope this helps people trying to implement Paging and some other nice stuff to you Umbraco projects.
UPDATE: found the video on GitHub in readme
These are all great answers, especially the pointer to Jeroen Breuer's library, but just in the name of being thorough and talking about all options -- if you are using jquery in your project and if you have relatively small result sets you could also go with a simple front end only solution.
You'd just bind the entire results list and then use a library like JPList (http://jplist.com ) as I have done here. Go to http://www.charterpublic.org/find-a-school/ and type in city Denver for example. You'll see there are 50+ results. I bind the entire results list then use jplist to make it sortable/pageable etc.
#if (results.Any())
{
<div class="list">
#foreach (var result in results.OrderByDescending(r => r.Name))
{
<div class="list-item">
//build your item
</div>
}
</div>
}
<div class="jplist-panel">
<!-- bootstrap pagination control -->
<ul class="pagination text-center jplist-pagination"
data-control-type="boot-pagination"
data-control-name="paging"
data-control-action="paging"
data-range="4"
data-mode="google-like"></ul>
<!-- items per page dropdown -->
<div class="hidden dropdown pull-left jplist-items-per-page"
data-control-type="boot-items-per-page-dropdown"
data-control-name="paging"
data-control-action="paging">
<button class="btn btn-primary dropdown-toggle"
type="button"
data-toggle="dropdown"
id="dropdown-menu-1"
aria-expanded="true">
<span data-type="selected-text">Items per Page</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdown-menu-1">
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="3">3 per page</a>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="5">5 per page</a>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="10" data-default="true">10 per page</a>
</li>
<li role="presentation" class="divider"></li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="all">View All</a>
</li>
</ul>
</div>
</div>
Then at the bottom of your view...
<script type="text/javascript">
$(document).ready(function () {
$('#demo').jplist({
itemsBox: '.list',
itemPath: '.list-item',
panelPath: '.jplist-panel'
});
});
</script>
There are other front end libraries that do this, but I found JPList the easiest to use for me.
The downside is it's not lazy loaded so it's a little heavier, but with smallish lists like mine here this was a great and simple solution.
I know that this is old , I used the Phil code recomendations and works very good.
But all the pages when incresing the pagination buttons works as infinite regeneration, what I mean is how can I do this as example:
Prev 123456789...Next and when is selected the page 5 for example shows like this:
Prev 5 6 7 8 9 10 11 12 13 ... Next and in the inverse or last page like this:
Prev ... 47 48 49 50 51 52 53 54 55
What I mean guys is to have just a 9 pages on click in the pagination buttons, but I need to implement with the same code that Phil Share :
#{
var pageSize = 8;
if(Model.Content.HasValue("numberOfItemsPerPage")){
pageSize = Model.Content.GetPropertyValue<int>("numberOfItemsPerPage");}
var page = 1; int.TryParse(Request.QueryString["page"], out page);
var items = Umbraco.TypedContent(Model.Content.Id).Children.Where(x => x.DocumentTypeAlias == "exampleAlias" && x.IsVisible());
var totalPages = (int)Math.Ceiling((double)items.Count() / (double)pageSize);
if (page > totalPages)
{
page = totalPages;
}
else if (page < 1)
{
page = 1;
}
foreach (var item in items.Skip((page - 1) * pageSize).Take(pageSize).OrderBy("createDate descending"))
{
<div class="example-div">
<h2>#item.GetPropertyValue("example")</h2>
</div>
}
if (totalPages > 1)
{
<div class="pagination">
<ul>
#if (page > 1)
{
<li>Prev</li>
}
#for (int p = 1; p < totalPages + 1; p++)
{
<li class="#(p == page ? "active" : string.Empty)">
#p
</li>
}
#if (page < totalPages)
{
<li>Next</li>
}
</ul>
</div>
}
}
Just to have a limit of 9 pages with the (...) according the page position.
Help!

How to lazy load content on JQuery tabs that doesn't pertain to any of the tab content(ie. login section or registration section)

I am lazy loading 3 tabs using Query tabs in an asp.net mvc web app. I have a Login section(username and password) that I would like to display where the tab content usually shows. I would like this Login section to only load when the user clicks the link at the top of the page. So, I need it lazy loaded too. How would I do that, I can't seem to figure it out. Below is my current tab code. I appreciate your help!
<script type="text/javascript">
$(document).ready(function()
{
$("#tabContainer").tabs();
});
</script>
<div id="menu" style=" background-color:White; width:950px; height:400px; float:left;">
<div id="tabContainer">
<ul>
<li>Home</li>
<li>Products</li>
<li>Contact Us</li>
</ul>
</div>
</div>
ok, you need to add the select: event onto your tabs code. here's a quick example:
<div id="menu" style=" background-color:White; width:950px; height:400px; float:left;">
<div id="tabContainer">
<ul>
<li>Home</li>
<li>Products</li>
<li>Contact Us</li>
</ul>
<div id="tab0"></div>
<div id="tab1"></div>
<div id="tab2"></div>
</div>
</div>
<script>
$(function() {
var $tabs = $("#tabContainer").tabs({
select: function(e, ui) {
var thistab = ui;
runMethod(thistab.index);
}
});
});
function runMethod(thistab) {
selectedtab = thistab;
switch (thistab) {
case 0:
getTab0Data();
break;
case 1:
getTab1Data();
break;
case 2:
getTab2Data();
break;
}
}
function getTab0Data(){
alert("you clicked Tab 0");
}
function getTab1Data(){
alert("you clicked Tab 1");
}
function getTab2Data(){
alert("you clicked Tab 2");
}
</script>
[EDIT] - i've updated the example so that it runs. both jquery base lib and jquery UI need to be referenced in the page. I also added a jsfiddle to demo it in action: http://jsfiddle.net/jimibt/k7ZN6/
basically, the getTab*n*Data() function(s) run an ajax request that populates the appropriate div (i.e. tab0, tab1, tab2 etc) as per the amended structure above.
for jquery ajax, see:
http://api.jquery.com/jQuery.ajax/
hope this helps

Categories