Best way to convert an ASP.NET MVC view to Angular - asp.net-mvc

I'm redesigning an existing ASP.net mvc page, which displays multiple client objects on a single page.
The reason why, is so the page can save all the clients/edits on a single click.
However as I wrote this 18 months ago it feels like their should be a better way to do it, as I have to use a FormBinder to map\save the objects, which is not pretty.
For example, I've started to use bootstrap tabs, each tab is a client and contains the details
<ul class="nav nav-tabs">
#foreach (var client in Model.Clients)
{
<li><a data-target="##client.ClientId" data-toggle="tab" href="##client.ClientId"><i class="fa fa-star"></i> #client.Name</a></li>
}
</ul>
<div class="tab-content">
#foreach (var client in Model.Clients)
{
<div class="tab-pane" id="#client.ClientId">
<div class="form-horizontal" role="form">
<div class="form-group">
<label for="#client.Name" class="col-sm-2 control-label">Name:</label>
<div class="col-sm-10">
#Html.TextBoxFor(model => client.Name, new { #class = "form-control", tabindex = "1"})
</div>
</div>
</div>
</div>
}
</div>
Is their a better, easier way to do this?
Ideally I don't want to use a form binder as well?
Thoughts? Examples?

I will say that as far as load time goes, Angular is going to help you a lot here. In your example, you will be loading the html for all of those tags once for each client. Angular would only load it once as a template, and duplicate the html on the client.
The angular equivalent would be something like this...
<div class="tab-content" ng-controller='ClientCtrl">
<div class="tab-pane">
<div class="form-horizontal" role="form">
<div class="form-group" ng-repeat="client in clients">
<label for="clientName" class="col-sm-2 control-label">Name:</label>
<div class="col-sm-10">
<input name='clientName' type='text' class='form-control' tabindex='1'>{{client.Name}}</input>
</div>
</div>
</div>
</div>
</div>
Granted, you'd have to do some work to implement the controller, but it's easy enough to do.
The benefits are that the scope is handling all of your ID's, so there is no need to keep track of any of that yourself. In some ways Angular is a difficult transition to learn, but once you do, it makes managing the code SO much easier.

Related

How to display loading message when waiting for asp.net to return to a new view

I have searched this a lot on the internet and I am looking for a way in where to display a loading message while asp.net is moving from one page to another. I have tried the load method from JavaScript but it does not work for moving from one page to another so how can I do this when a search button is clicked.
#using (Html.BeginForm("SearchResult", "Home", FormMethod.Get))
{
<section class="search-sec">
<div class="container-fluid">
<form>
<div class="row">
<div class="col-lg-12">
<div class="row">
<div class="col-lg-4 col-md-3 col-sm-12 p-0">
<input type="text" name="searchTitle" class="form-control search-slt" placeholder="Job Title, Skills, Company!">
</div>
<div class="col-lg-4 col-md-3 col-sm-12 p-0">
<input type="text" name="searchLocation" class="form-control search-slt" placeholder="Location">
</div>
<div class="col-lg-4 col-md-3 col-sm-12 p-0">
<button type="submit" value="Create" class="btn btn-danger wrn-btn">Search</button>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
}
If you are not using ajax then you could load the new page with a loading message and remove it when the load is complete. I used this one in one of my projects (https://ihatetomatoes.net/create-css3-spinning-preloader/). Basically you activate or deactivate adding a class to the html body.
In the view where I want to show it before anything else i put this:
<script>
$('body').removeClass('loaded');
</script>
and once everything is loaded :
<script>
//...other stuff
$(document).ready(function () {
setTimeout(function () {
$('body').addClass('loaded');
}, 500);
});
</script>
But you would still have time of wait before reaching the page, you should capture the search click and show the loader before leaving the first page.
Anyways I agree with Jerdine and daremachine, you would have more control loading with ajax the search results and showing them in the same page. Maybe is not possible so I hope the workaround works for you

Setting Data-Parent and HREF dynamically in a for-loop

Previously to create Accordion controls I used to use this piece of code:
<div class="panel-group" id="accordionMessagesSetup">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordionMessagesSetup" href="#collapseMessagesSetup">
<span class="glyphicon glyphicon-chevron-up"></span>
Message Setup
</a>
</h4>
</div>
<div id="collapseMessagesSetup" class="panel-collapse collapse in">
<div>
<p style="background-color: red"> Someting ELSE in here</p>
<p style="background-color: red"> Someting ELSE2 in here</p>
</div>
</div>
</div>
</div>
or as seen here: Bootplay Live Demo
Now I still want to use my example but in this page I have a for-each loop so I need to create these at run-time.
The items I need to put variables there in order for this to work are
id="accordionMessagesSetup"
data-parent="#accordionMessagesSetup"
href="#collapseMessagesSetup"
id="collapseMessagesSetup"
How can I initialize those in a for-each loop a mode using Razor?
Imagine you have whatever property you like to do it in the model.
The biggest issue you are/will likely run into is Razor parsing. When you try to use a Razor variable in the middle of some bit of text, often Razor cannot determine where the variable name ends. For example, if you were to do something like:
<div id="accordion#Model.IdMessageSetup">
Razor thinks it needs to look for a property on the model named IdMessageSetup, when actually, you just wanted Id. The easiest way to fix this is to wrap the variable in paranthesis:
<div id="accordion#(Model.Id)MessageSetup">
Now, it's clear which part is the variable. As far as adding the # sign goes, I'm not really sure what the confusion is there. You just put it where it needs to go:
<a href="#collapse#(Model.Id)MessagesSetup">
Nothing special required.

How can I create a re-usable custom HTML panel in ASP.NET MVC?

I am trying to create a re-usable UI element in ASP.NET MVC that wraps around whatever content I choose to place in it. My first thought was to create a partial view, but that doesn't seem to help me in what I am trying to accomplish.
The Template
For example I would like to create some re-usable markup similar to this (please excuse the pseudo-code):
<div class="panel panel-default">
<div class="panel-body">
#RenderBody()
</div>
</div>
A Simple Example
Then in my views I would like to do something similar to this:
#Render.Partial("MyPanel")
{
<img src="image.jpg" />
}
Assuming that code worked as expected it would generate the following:
<div class="panel panel-default">
<div class="panel-body">
<img src="image.jpg" />
</div>
</div>
Another Example, with more complex markup
Theoretically I would like to be able place any and everything I would like within one of the panels. So even more complex markup would still appear legible.
#Render.Partial("MyPanel")
{
<form>
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
</div>
<div class="form-group">
<label for="exampleInputFile">File input</label>
<input type="file" id="exampleInputFile">
<p class="help-block">Example block-level help text here.</p>
</div>
<div class="checkbox">
<label>
<input type="checkbox"> Check me out
</label>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
}
Just like in the first example, it would wrap everything inside the header and footer of my template:
<div class="panel panel-default">
<div class="panel-body">
<form>
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
</div>
.. truncated ..
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
Known Possibilities
Partial View. A partial view seems to make sense, except I have been unable to figure out a way to create a partial that has flexibility beyond the Model it was designed for. I gave two examples, because the contents within my panel could be significantly different each time I use it. I would like to be able throw anything into the body of this partial view; text, markup, more razor code, etc.
HTML Helper. This works great when I have specific parameters I would be passing in. I don't see this as practical when needing to enter large amounts of markup, as it would become hard to read/maintain. Also since html would be passed in as a string, I'm not sure how this would work with razor tags?
2 Partial Views. Using one as the header and the other as the footer. This works, but it just feels sloppy to me.
I was able to do this in ASP.NET WebForms by creating a custom control. It seems like this is something that should be straight forward in MVC too, but I just haven't quite been able to figure out a good solution yet.
You can use "DynamicInvoke" to create html helpers with dynamic markup, such as:
public static IHtmlString CustomPanel(this HtmlHelper htmlHelper, Func<object, object> panelMarkup = null)
{
return CustomPanel(htmlHelper, (panelMarkup == null ? "" : panelMarkup.DynamicInvoke(htmlHelper.ViewContext).ToString()));
}
public static IHtmlString CustomPanel(this HtmlHelper htmlHelper, string content)
{
TagBuilder div = new TagBuilder("div");
div.AddCssClass("panel panel-default");
TagBuilder innerDiv = new TagBuilder("div");
innerDiv.AddCssClass("panel-body");
innerDiv.InnerHtml = content;
div.InnerHtml = innerDiv.ToString();
return new HtmlString(div.ToString());
}
And then you would use it like this:
#Html.CustomPanel(
#<text>
<div>My Custom Markup</div>
<span>More Stuff</span>
</text>
)
Your final content will look like:
<div class="panel panel-default">
<div class="panel-body">
<div>My Custom Markup</div>
<span>More Stuff</span>
</div>
</div>
You see this used often in some 3rd party widget libraries (kendo-ui is the main one i know of)
There are many ways to create reusable content in MVC, but they all have various pros and cons. For instance, custom Html helpers are a common method, but they require writing a lot more code than you probably want.
You can certainly use partial views, just pass a model containing the content you want to render to the partial... but that can also be a little confusing as well.
I think what you may be looking for are Razor Helpers. These are explained in more detail here:
http://weblogs.asp.net/scottgu/asp-net-mvc-3-and-the-helper-syntax-within-razor
However, the basic structure would look like this:
#helper MyHelper(string content)
{
<div class="panel panel-default">
<div class="panel-body">
#Html.Raw(content)
</div>
</div>
}
Then you use it like this:
#MyHelper("<img src="image.jpg" />")
You don't have to use strings, you could use structured content, models, etc.. you can use other helpers inside. You can re-use them as described later in the article.
You might want to start thinking about your pages as more data-centric, however. If you use EditorTemplates to render your data then you render controls based on the type of your data rather than rendering your pages and trying to adapt your pages to contain your data.

Using an HTML Action Link to target a div

I am new to ASP/MVC and I am having trouble figuring out how to link a div to a page in HTML markup. This is the current link in pure HTML. I want to accomplish this, but in razor syntax
<div class="col-md-2">
<a href="ambulance.html">
<div class="amb item">
<div class="tiletext">AMB</div>
<div class="tilesubtext">Ambulance</div>
</div>
</a>
</div>
I've been looking into action links, but if there is a better way to accomplish this, I'm open to it!
Possible duplicate. I'll add a bit of explanation that pertains to the question since it has to do with Razor:
What your backend developer needs is Url.Action helper. This will let you route the link through the MVC framework.
So say:
<div class="col-md-2">
<a href="#Url.Action("Cars", "Ambulance")">
<div class="amb item">
<div class="tiletext">AMB</div>
<div class="tilesubtext">Ambulance</div>
</div>
</a>
</div>
ASP.NET MVC: generating action link with custom html in it
Html.ActionLink method only creates anchor tags for some action method, you need Url.Action method. Using the rest of the markup is fine.
<div class="col-md-2">
<a href="#Url.Action("Index","Home")">
<div class="amb item">
<div class="tiletext">AMB</div>
<div class="tilesubtext">Ambulance</div>
</div>
</a>
</div>

PartialViews Messing With Eachother

I have the following _Layout.cshtml page that has a bunch of #Html.Action() calls to several partial views.
<div class="wrapper">
<div class="header">
<a style="text-decoration:none;" href="#Url.Action("Index", "Home")"><div class="logo"><p>fisharwe</p><span class="greenText float-right">:</span></div></a>
<div class="searchBar">
#Html.Action("Search", "Item")
</div>
<div id="hearGreenBar"></div>
</div>
<div class="pageContent">
#RenderBody()
</div>
<div class="rightColumn">
<div id="help">
<div id="allHelpContent">
<span id="helpIcon"></span> <span id="helpTitle">help</span> <span id="helpArrow"></span>
</div>
</div>
<div id="userPanel">
#if(!Request.IsAuthenticated)
{
<div id="loginForm">#Html.Action("Login", "User")</div>
<div id="registerForm">#Html.Action("Register", "User")</div>
<hr class="greyLine" />
<div id="recentlyViewedItems">
<div id="recentItemsTitle">
<span class="recentItemsIcon"></span><span class="theRecentTitle">Recently Viewed</span>
</div>
</div>
}
else
{
<div id="userInfoSummary">#Html.Action("Summary", "User")</div>
}
</div>
</div>
</div>
At the top you can see the #Html.Action("Seach", "Item") call which renders a search bar and allows users to search for items/categories/sub-categories...etc. I got this working now, but it generated a new problem! When the user searches for something, and the results are rendered, the Login and Register partials in the sidebar (userPanel) are displaying validation errors such as "Email cannot be empty". I understand that the View is rendered regardless of what partial posted back but there has to be a way to prevent that from happening... Do I have to get rid of partials and render everything into the _Layout.cshtml page? But in that case I need to make this page typed which will cause yet another issue... So what can be done? I'm open to any suggestions...
Thank you.
Do you have different forms for the search and what is in the "userPanel"?. You may want to make sure your search is doing a get and not a post.
#using (Html.BeginForm("Search", "YourController", FormMethod.Get))

Resources