Truncate model property in ASP.Net MVC - asp.net-mvc

Im currently using a truncate and texteditor in different way. And both is working fine but I facing this problem. I want to truncate a text inside the texteditor. T_T
Im using truncate this way and its working
#helper Truncate(string input, int length)
{
if (input.Length <= length)
{
#input
}
else
{
#input.Substring(0, length)<text>...</text>
}
}
#foreach (var item in Model)
{
<div>
#Truncate(item.DetailDescription, 400)
</div>
}
AND
Im declaring raw to call a texteditor this way and its also working fine
#html.Raw(item.DetailDescription)
PROBLEM: How could I possibly combine the two in a single function? Is this even possible T_T

It's always better to put the business logic inside the model.
I would have done this in the model itself adding another property 'TruncatedDescription'.
public string TruncatedDescription
{
get
{
return this.DetailDescription.Length > 400 ? this.DetailDescription.Substring(0, 400) + "..." : this.DetailDescription;
}
}
So you can use this in the View directly
#foreach (var item in Model)
{
<div>
item.TruncatedDescription
</div>
}
If you are following this method, you can use item.TruncatedDescription in the text-editor with out help of html.Row as this won't be HTML encoded.

I've done like this one before. I did it this way.
#helper Truncate(string input, int length)
{
if (input.Length <= length) {
#Html.Raw(input)
} else {
var thisString = input.Substring(0, length);
#Html.Raw(thisString)
}
}
I combined raw inside the truncate helper then I call the Truncate this way
#Truncate(item.DetailDescription, 400)

Related

Move Processing from the View to a controller

Currently we have a view that does some heavy processing to create an XML css feed that we send to a client. Here is a snippet of code that does some processing:
#foreach (Models.BVModels cat in ViewBag.BVSubCategories)
{
<Category>
#if (!string.IsNullOrEmpty(cat.LinkName))
{
<ExternalId>(cat.LinkName)</ExternalId>
}
else
{
<ExternalId>cat.Title</ExternalId>
}
<ParentExternalId>cat.ParentName</ParentExternalId>
<Name>cat.Title</Name>
#if (cat.Brand.ToLower() == "[hardcoded value]" && !string.IsNullOrEmpty(cat.ID))
{
if (!string.IsNullOrEmpty(cat.LinkName) && !string.IsNullOrEmpty(cat.ParentName))
{
<CategoryPageUrl><![CDATA[[URL]/gallery/#cat.ParentName.ToLower()/#cat.LinkName.ToLower()]]></CategoryPageUrl>
}
string imageName = cat.ID + ".jpg";
<ImageUrl>[URL]/imageeditor/#imageName</ImageUrl>
}
else if (cat.Brand.ToLower() == "[BRAND]")
{
if (!string.IsNullOrEmpty(cat.LinkName))
{
<CategoryPageUrl><![CDATA[[URL]/product/category/#cat.ID/#cat.LinkName.ToLower()]]></CategoryPageUrl>
}
string imagename = cat.ID + ".jpg";
<ImageUrl>[URL]/image/getdvimagebypageidandimageid/#cat.ID/1/#imagename</ImageUrl>
}
else
{
if (!string.IsNullOrEmpty(cat.LinkName))
{
<CategoryPageUrl>[URL]</CategoryPageUrl>
}
}
</Category>
}
I need to move this to a controller instead of keeping this on the view. This was done quickly to create the feed at one time, but now is way to slow. Not to mention there are a lot of hard coded values and some processing that needs to be cleaned up. Right now this cshtml page does not have a #model directive it is pulling the data from the ViewBag. I want to push this to the controller and clean up this page. Can I pass the ViewBag to the Controller and process? I am rusty on MVC and could a small shove in the right direction. So I want to call this controller ActionResult pass in the ViewBag and return an XML string that has been formatted as below.
Thanks.
I created a new controller for the feed that pulls the data from the database and return it in collections that I can iterate over and return the XML string. This replaced the long processing (20 minutes) over the ViewBag. Now I will tighten up the code and put some scrubbing in place to clean it up.
THanks.
John

Razor View Flow

Having a brain fart... given this model:
public class Result
{
public decimal Cost {get;set;}
}
And this extreme simplified view:
#{
decimal resultsTotal = 0;
}
<div>#resultsTotal</div> //need the total from the loop below here
#foreach(var result in Model.Results)
{
resultsTotal += result.Cost;
<div>#result.Cost</div>
}
I need to display the resultsTotal variable above the foreach loop. I realize I can #Model.Results.Sum(x => x.Cost) in the view, the model or the controller, the point is I want to avoid enumerating Results more than once. Is there away to buffer the results and update the div after looping through perhaps or? Yea I could also use jquery, but that smells.
You could use a helper and write the results to a buffer:
#{
IEnumerable<Result> results = Model.Results;
decimal resultsTotal = 0;
var buffer = new List<HelperResult>();
}
#foreach(var result in Model)
{
resultsTotal += result.Cost;
buffer.Add(ResultRow(result))
}
<div>#resultsTotal</div>
#foreach (var result in buffer)
{
#result
}
#helper ResultRow(Result result)
{
<div>#result.Cost</div>
}
#{
IEnumerable<Result> results = Model.Results;
#foreach(var result in Model=)
{
<div>#result.Cost</div>
}
var resultsTotal = Model.Results.Sum(x => x.Cost)
}
<div>#resultsTotal</div>
#{} is a code block that you can use to execute code. I wouldn't recommend doing it this way, as putting logic in the view is just down right dirty.
You should make this calculation within your controller's action method and pass it to your view via the model.
Something along the lines of this...
public ActionResult Index()
{
// ... get your results from wherever you got them from before, eg your service ...
IEnumerable<Result> results = myService.GetResults();
decimal resultsTotal = 0;
var responseModel = new YourViewModel
{
Results = results,
ResultsTotal = results.Sum(x => x.Cost)
};
return View(responseModel);
}
And then you can display the information that has been calculated already within your controller on the view, with a minimal amount of logic:
#foreach(var result in Model.Results)
{
<div>#result.Cost</div>
}
<div>#Model.ResultsTotal</div>
Move the logic out of your view and into your view model. Unfortunately, you haven't made very clear what type of calculations you're desiring to make, but, in general, just add properties on your view model(s) that return the results of those calculations and you can chain them if need be. For example:
public class MyAwesomeViewModel
{
public List<Result> Results { get; set; }
public decimal Total
{
get { return Results.Sum(x => x.TotalCost);
}
public decimal AverageCost
{
get { return Total / Results.Count(); }
}
}
public class ResultViewModel
{
public decimal TotalCost
{
get { return Cost + Tax + Shipping; }
}
}
Much as your example, I've just made up some stuff here to illustrate the point. Break down your calculations into discreet units and then build them back up. This not only simplifies the calculations, but also gives you access to component calculations, should you need them. Then, you can keep your view relatively logic free.

How to replace all Character or value in mvc View Page by Replace?

#Html.EditorFor(model => model.number.Replace("_","*"))
input:- 12_34
I it give's o/p like this :- 12*34
but i want * How could i get this result?
and ALSO i Want 1***4 ?
Please Help me...
i Want 1***4 ?
A simple extension method would do, as shown below. Please add more validations as per your requirements.
public static class Extensions
{
public static string GetString(this string input)
{
var arr = input.ToCharArray();
for (int i = 1; i < arr.Length - 1; i++)
{
arr[i] = '*';
}
return new string(arr);
}
}
Can be invoked as -
string str = "1wfqEGFE1234562_3453".GetString();
Output will be - 1******************3
This method just generates HTML markup, if you need to replace the content of the textbox typed by the user, you should do that on code behind after the submit or via javascript.

MVC Razor: Helper method to render alternate content when empty

I've got some data, and sometimes that data is blank. Instead of making a bunch of crazy logic on my view I'd rather use a helper method that will render the data if it exists, and render some HTML that just says "N/A" when the string is empty/null.
Ideal syntax: #Helpers.RenderThisOrThat(Model.CustomerPhone)
If the Model.CustomerPhone (a string) is empty it will render this alternate HTML instead: <span class='muted'>N/A</span>
Here's what we have so far:
#helper RenderThisOrThat(string stringToRender, string methodToGetAlternateText = null)
{
#RenderThisOrThat(MvcHtmlString.Create(stringToRender), methodToGetAlternateText)
}
#helper RenderThisOrThat(MvcHtmlString stringToRender, string methodToGetAlternateText = null)
{
if (string.IsNullOrWhiteSpace(stringToRender.ToHtmlString()))
{
if (!string.IsNullOrWhiteSpace(methodToGetAlternateText)) {
#methodToGetAlternateText
}
<span class='muted'>N/A</span>
}
#stringToRender
}
This works just fine until we want to pass something other than a string into either parameter. For example when we have an email address we want it to be a link to that email and not just the string of the email.
#Helpers.RenderThisOrThat(##Html.DisplayFor(m => m.CustomerEmail))
It gives us the error: "Cannot convert lambda expression to type 'string' because it is not a delegate type"
We are at a loss for how to make this work... any help here?
You're looking for a helpers that will take a string and:
If the string is not empty, render that string.
If the string is not empty, render a given template.
If the string is empty, render "N/A" html.
If the string is empty, render a given template.
When passing a razor block to a function as a parameter, razor packages the block as Func. Change the parameters in the helper functions to take that type of delegate and don't forget to call those delegates (I chose to pass null).
These helpers should handle those scenarios.
Solution
#helper RenderThisOrThat(string stringToRender, Func<object, IHtmlString> leftTemplate = null, Func<object, IHtmlString> rightTemplate = null)
{
var shouldRenderLeft = !string.IsNullOrWhiteSpace(stringToRender);
leftTemplate = leftTemplate ?? (o => MvcHtmlString.Create(stringToRender));
#RenderThisOrThat(shouldRenderLeft, leftTemplate, rightTemplate)
}
#helper RenderThisOrThat(bool shouldRenderLeft, Func<object, IHtmlString> leftTemplate, Func<object, IHtmlString> rightTemplate = null)
{
var shouldRenderRight = !shouldRenderLeft;
if (shouldRenderRight)
{
if (rightTemplate != null)
{
#rightTemplate(null)
}
else
{
<span class='muted'>N/A</span>
}
}
else
{
#leftTemplate(null)
}
}
Examples
1. #Helpers.RenderThisOrThat(Model.StringWithBob)
2. #Helpers.RenderThisOrThat(Model.StringWithNull)
3. #Helpers.RenderThisOrThat(Model.StringWithBob, #<span>I'm #Model.StringWithBob</span>)
4. #Helpers.RenderThisOrThat(Model.StringWithNull, #<span>I'm #Model.StringWithBob</span>)
5. #Helpers.RenderThisOrThat(Model.StringWithBob, #<span>I'm #Model.StringWithBob</span>, #<span>What about Bob?</span>)
6. #Helpers.RenderThisOrThat(Model.StringWithNull, #<span>I'm #Model.StringWithBob</span>, #<span>What about Bob?</span>)
Will output:
Bob
<span class='muted'>N/A</span>
<span>I'm Bob</span>
<span class='muted'>N/A</span>
<span>I'm Bob</span>
<span>What about Bob?</span>
This is an awfully complex solution to a simple problem. You don't need to create complex views, in fact, you should be using an Editor/DisplayTemplate, then you put your logic in the template and it's done once, without all the need for extra inclusion of helper functions, or anything else.
You can also go a step further here, because in this case you're rendering an email address. You apply a DataType attribute to your model and then specify an Phone Number rendering type.
public class MyModel {
[DataType(DataType.PhoneNumber)]
public string PhoneNumber {get;set;}
}
Then you create a folder in ~/Views/Shared called DisplayTemplates and in that folder create a file called PhoneNumber.cshtml, in it you do this:
#model string
#if (string.IsEmptyOrWhiteSpace(Model)) {
#:<span class='muted'>N/A</span>
} else {
#: <span>#Model</span>
}
Then, in your view:
#Html.DisplayFor(x => x.PhoneNumber)
That's it, no complex logic in your view, no convluted helper functions everywhere. This is simple, easy, and maintainable. You can do the same for Email address as there is an EmailAddress datatype as well.
MVC has a lot of very good functionality built-in that most people simply do not use, because they haven't spent any real time learning it.

Having problems with C# inside of my Razor view

I have the following code:
string init = "yes";
string html = "";
foreach (var item in v.Details) {
if (item.Substring(0, 1) != " ")
{
if (init != "yes")
{
html += "</ul>";
}
html += "<p>" + item + "</p><ul>";
}
else
{
html += "<li>" + item.Substring(1) + "</li>";
}
}
The code is in my MVC controller and it creates a string called html. The thing is I don't think it should be in the controller. I tried to put this into the view and ended up with a huge mess that doesn't seem to work. Seems I am not very good at coding C within a razor view. I just saw a lot of syntax type errors and confusion between what's C and what's HTML.
Can anyone suggest how I could make this code work within a view. Here's what I used to have:
<ul>
#foreach (var item in Model.Details)
{
<li>#item</li>
}
</ul>
This worked but as you can see I now need more processing. Would it be better to take this out of the view and if so how could I do this. I'm really hoping for a view solution but I am confused about where the put the #'s and where to put the brackets.
Any experts at coding C inside or Razor out there?
The code is in my MVC controller and it creates a string called html.
The thing is I don't think it should be in the controller
You are correct. It shouldn't be in the view neither due to the absolute mess it would create. I think this code is better suited in a custom HTML helper:
public static class HtmlExtensions
{
public static IHtmlString FormatDetails(this HtmlHelper htmlHelper, IEnumerable<string> details)
{
var init = "yes";
var html = new StringBuilder();
foreach (var item in details)
{
if (item.Substring(0, 1) != " ")
{
if (init != "yes")
{
html.Append("</ul>");
}
html.AppendFormat("<p>{0}</p><ul>", htmlHelper.Encode(item));
}
else
{
html.AppendFormat("<li>{0}</li>", htmlHelper.Encode(item.Substring(1)));
}
}
return MvcHtmlString.Create(html.ToString());
}
}
which you would invoke in your view:
#Html.FormatDetails(Model.Details)
Remark: there seems to be something wrong with the init variable. You are setting its value to yes initially but you never modify it later.

Resources