Deciding content of html tag based on a conditional in mvc3 asp.net - asp.net

This sounds really basic yet I couldn't find the answer.
I pass a Message struct to the View and I want to display it.
If the Message.Category field is "Technical" I want to display "Technical Problem" else just display it as it is.
How do I make the view understand that Technical Problem isn't a statement but html text I want to display?
My code:
<span class="cright" id="cat">
#{
if (String.Compare(ViewBag.Message.Category, "Technical") == 0)
{
Technical Problem <----THIS
}
else #ViewBag.Message.Category
}
</span>
More info:
I'm working on a messaging system. Users create a message and as it is being sent they can view it. The category is compulsory (Question, Suggestion or Technical Problem) and to avoid redundancy in the database I truncate the last option to just 'Technical', however when the users view their sent message I want it to show up in full.
Thanks everyone; from all your answers I arrived at:
<span class="cright" id="cat">
#if (ViewBag.Message.Category == "Technical ")
{<text>Technical Problem</text>}
else
{<text>#ViewBag.Message.Category</text>}
</span>
which works just as I wanted.

Original Answer
if(ViewBag.Message.Category == "Technical")
{
<span>Technical problem</span>
}
else
{
<span>Problem is : #(ViewBag.Message.Category)</span>
}
Updated Answer
//Model
public class Message
{
public int ID {get; set;}
public string Message {get; set;}
public string Category {get; set;}
}
//Controller
public ActionResult Index()
{
//If you use Linq to Sql, I made this up but this should give you an idea
using(MessageDataContext context = new MessageDataContext())
{
var messages = context.Messages.Where(m => m.Category == "Technical")
.Select(m => new Message { ID = m.ID, Message = m.Text, Category = m.Category});
return View(messages);
}
}
//View
#model IEnumerable<Message>
#foreach(var message in Model)
{
if(message.Category == "Technical")
{
//Id and class will be "TechnicalMessage1"
//Now you can create css class called "TechnicalMessage1" and only message with Id = 1 will have it
<span id="#(message.Category)Message#(message.ID)" class="#(message.Category)Message#(message.ID)">Technical problem</span>
}
else
{
<span>Problem is : #(ViewBag.Message.Category)</span>
}
}

You can use
<text>Technical Problem</text>
for this.

Is this what you are looking for?
#("Technical Problem")
alternatively
<text>Technical Problem</text>
alternatively
#:Technical Problem
Read http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx for the syntax ..

Related

Creating Webservice with webmatrix

this time i learn how to create webservice with webmatrix.
I try learn from this link :
http://www.microsoft.com/web/post/creating-a-webservice-with-webmatrix-and-consuming-it-with-a-windows-7-phone-application
but i stuck because author didn't sample source code.
This is my getproduct.cshtml code :
#{
public class Product {
public string Name {get; set; }
public int Price {get; set; }
}
public static Product GetProducts(string price) {
var db = Database.Open("WebService");
var selectQueryString = "SELECT Name, Score FROM Users WHERE Score >= " + #price;
var data = db.Query(selectQueryString);
Product product = new Product();
foreach (var row in data) {
product.Name = #row.Name;
product.Price = #row.Score;
}
return product;
}
}
This is my jsonRequest.cshtml code :
#{
var price = Request.QueryString["price"];
if (price == null || price == string.Empty) {
<p>Please enter a Price value</p>
} else {
var product = getproduct.GetProducts(price);
Json.Write(product, Response.Output);
}
}
okay and last i run http://localhost:55278/jsonRequest.cshtml, but there are two error for me, that are :
1. that address there is no QueryString, and code just past if to else.
2. error in getproductGetProduct(price);
CS0117: 'ASP.getproduct' does not contain a definition for
'GetProduct'
please help me, how to solve my problem, so that i can finish that tutorial from that link.
thank you
---UPDATE----
this is my folder
Test Webservice
|-jsonRequest.cshtml
|-App_Code
|-getproduct.cshtml
The first issue I can see is just one of case-sensitivity:
var product = getproduct.GetProduct(price);
Should be:
var product = getProduct.GetProduct(price);
The object name is case-sensitive and must be exactly the same as the name of the .cshtml file in the App_Code folder.
You seem to have edited your question to show that the case was correct originally, so the next problem I see is in the name of your method being plural. Your method signature is:
public static Product GetProducts(string price)
So you need to change:
var product = getproduct.GetProduct(price);
To:
var product = getproduct.GetProducts(price);
In your getproduct.cshtml you need to change the opening of the block from #{ to #functions {.
I know you're only following a tutorial too so this is just an aside, but that code looks absolutely ripe for an SQL injection hack to me.

ASP.NET MVC Conditional ViewModel Abstraction

I am new to ASP.NET MVC and I am stuck on a point. I am working on a classified site. My situation is, I have a lot of categories in which a user can post their ads and each ad category have different View. I have created a Controller Action like
public ActionResult PostAd(string CategoryName, string SubCategoryName)
{
if(categoryName == "Vehicle" && SubCategoryName == "Cars")
{
var model = new CarAdViewModel();
// set CarAdViewModel properties...
return View("CarAdCreateView", model);
}
else if(categoryName == "Vehicle" && SubCategoryName == "Bikes")
{
var model = new BikeAdViewModel();
// set BikeAdViewModel properties...
return View("BikeAdViewModel", model);
}
else if(categoryName == "Property" && SubCategoryName == "RentHouse")
{
var model = new RentHouseAdViewModel();
// set RentHouseAdViewModel properties...
return View("RentHouseAdViewModel", model);
}
else................... so on and so on
}
My problem is I have huge number of Categories and Sub Categories almost 60+. And if I keep on coding like above for 60+ categories and subcategories, my PostAd method is going to blast and become unmanageable.
Please tell me some best practice or pattern which can bring me out of this problem.
Unfortunately, some of what you are doing cannot be avoided. There needs to be some form of model and view selection based on category.
Use a factory pattern. Create a base class:
public abstract class BaseCategory
{
public abstract string GetViewName();
public abstract Object CreateModelFromFormData();
}
For each category, create a sub-class derived from BaseCategory and implement the abstract functions.
In your action, do the following:
public ActionResult PostAd(string categoryName, string subCategoryName)
{
BaseFactory factory;
if (categoryName == "Vehicle")
{
if (subCategoryName == "Cars")
{
factory = new CarsFactory();
}
else ...
}
else ...
return View(factory.GetViewName(), factory.CreateModelFromFormData());
}
I have a couple reasons for this schema:
I am purposefully using if/else for the factory selection. Your controller is going to be created and re-created for every action call. So pre-populating a list will constantly and needlessly create objects for categories that will not be selected. A simple if/else will be more efficient. If you want to prevent the if/else, you can put your factories in a Dictionary and select based on the categories, but that would be a lot of needless constructor actions.
I made the CreateModelFromFormData a function because I assume you'll need to copy data from the posted form data. This may require passing in data, but I left the function parameterless.
I used base/derived classes because the copying of the form data will probably need to be custom from the model being created and the form data being posted. Also, saving to persistent storage (file or database) may be category-specific as well.
It would be one of some possible solutions
public class PostAdData
{
public string CategoryName;
public string SubCategoryName;
public string ViewName;
public Type Model;
}
public class PostController : Controller
{
private readonly List<PostAdData> _theData;
public HomeController()
{
_theData = InitializeData();
}
public ActionResult PostAd(string categoryName, string subCategoryName)
{
var data = _theData.FirstOrDefault(c => c.CategoryName == categoryName && c.SubCategoryName == subCategoryName);
if (data != null)
{
var model = Activator.CreateInstance(data.Model);
return View(data.ViewName, model);
}
return View("Error");
}
[NonAction]
public List<PostAdData> InitializeData()
{
var result = new List<PostAdData>
{
new PostAdData
{
CategoryName = "Vehicle",
SubCategoryName = "Cars",
ViewName = "CarAdCreateView",
Model = typeof (CarAdViewModel)
}
};
return result;
}
}
You should make this data driven. You create a lookup table that has a compound primary key of category and subcategory. Then it has a table with View in it. Then you simply ad rows for each category/subcategory/view combination.
If you absolutely don't want a database, then you can use a simple hashset or dictionary.
var views = new Dictionary<Tuple<string,string>,string>();
views.Add(new Tuple<string,string>("Vehicle", "Cars"), "CarAdCreateView");
Then in your PostAd you just lookup the correct view.
What a beautiful solution on www.asp.net to my question, here is the link : http://forums.asp.net/t/1923868.aspx/1?ASP+NET+MVC+Conditional+ViewModel+Abstraction
Edit:
My code is :
public class AdsController : Controller
{
private readonly IAdService _adService;
public AdsController(IAdService adService)
{
_adService = adService;
}
public ActionResult PostAd(string Category, string SubCategory)
{
//Here I will call
var strategy = GetStrategy(CategoryName, SubCategoryName);
strategy.FillModel(_adService );
return View(strategy.ViewName, strategy.Model);
}
}

Model binder data issue from a EditorTemplate

I'm showing in a List in a Razor view. In it I have several Editor templates that are displayed in the list view. Here is my editor template.
#using Contoso.MvcApplication.Extensions
#model Contoso.MvcApplication.ViewModels.MultipleChoiceQuestionViewModel
<h5>#Model.Question.QuestionText</h5>
<div>
#Html.RadioButtonForSelectList(m => m.Question.SelectedAnswer, Model.AnswerRadioList)
#Html.ValidationMessageFor(m => m.Question.SelectedAnswer)
</div>
The issue is where I set the RadioButtonForSelectList, it's binding so so, because I know at this situation should be inside a for loop like this:
#Html.RadioButtonForSelectList(m => m[i].Question.SelectedAnswer, Model.AnswerRadioList) // the index
But from the Editor template, I have no way to know the index inside a lambda expression.
This is the site where I copied the html extension from:
http://jonlanceley.blogspot.mx/2011/06/mvc3-radiobuttonlist-helper.html
And here is the view model that I'm using
public class MultipleChoiceQuestionViewModel
{
public MultipleChoiceQuestion Question { get; set; }
public List<SelectListItem> AnswerRadioList { get; set; }
}
How do I correctly bind the radioButton?
When I read the tag in code, all the models in my list have the same id: Question.SelectedAnswer. I assume this is wrong, because there should be an indexed ID like so: Question.SelectedAnswer.[INDEX].
UPDATE:
public ActionResult Index(short testId)
{
GenerateQuiz(testId);
StartQuiz();
return View(CreateQuestionViewModel((MultipleChoiceQuestion)CurrentQuestion));
}
[HttpPost]
public ActionResult Index(MultipleChoiceQuestionViewModel q)
{
// Save answer state
((MultipleChoiceQuestion)CurrentQuestion).SelectedAnswer = q.Question.SelectedAnswer;
if (CurrentNumber == Questions.Count - 1)
{
QuizCompleted();
return RedirectToAction("ShowResults");
}
else
{
NextQuestion();
return View(CreateQuestionViewModel((MultipleChoiceQuestion)CurrentQuestion));
}
}
The part of the view that displays the questions should look like this:
#for (int j = 0; j < Model.Questions.Count; j++)
{
<h5>
Model.Questions[j].QuestionText
</h5>
<div>
#Html.RadioButtonForSelectList(m => m.Questions[j].SelectedAnswer, Model.AnswerRadioList)
</div>
}

Import two or multiple class models to a single controller on ASP.NET

I'm very new to ASP.NET, but I know a little programming in Java. I want to use a ZIP code to query a database which will return a string, then use that string to query another database. I wanted to do this on the same control model. I thought it would be easy, and it sounds pretty easy.
When I created the controller, I put the model class of the first database, and, so far, I've gotten as far as querying the first database, but now that I have the string I want to query a second database through the DBEntities.
This displays an error saying:
> The model item passed into the dictionary is of type
> 'System.Collections.Generic.List`1[FinalBallot.Models.AgainCandidate]',
> but this dictionary requires a model item of type
> 'System.Collections.Generic.IEnumerable`1[FinalBallot.Models.ZipTable]'.
Is there a way to solve this in an easy way?
public class Default1Controller : Controller
{
private CandidatesDBEntities db = new CandidatesDBEntities();
public string districString = "";
//
// GET: /Default1/
public ViewResult Index(string searchString)
{
var queryZip = from s in db.ZipTables select s;
var queryCandidates = from s1 in db.AgainCandidates select s1;
double sT = 0;
//method so it doesnt display the whole db
if (String.IsNullOrEmpty(searchString))
{
queryZip = queryZip.Where(s => s.ZipL.Equals(0));
}
if (!String.IsNullOrEmpty(searchString))
{
sT = double.Parse(searchString);
queryZip = queryZip.Where(s => s.ZipL.Equals(sT));
try
{
districString = queryZip.ToList().ElementAt(0).District;
}
catch
{
}
if (!String.IsNullOrEmpty(districString))
{
queryCandidates = queryCandidates.Where(s1 => s1.District.Equals(districString));
}
}
return View(queryCandidates.ToList());
}
In your view, did you specify the model to be IEnumerable<ZipTable>? The model that you're passing to your view is IEnumerable<AgainCandidate>, so you would get an error if you specified your model as something else. You'd need to change the model in your view to be IEnumerable<AgainCandidate>.
UPDATE:
Based on your revised explanation, you can do a couple things:
1) create a "ViewModel" that has two properties for each of your collections you want to display on the page like so:
public class MyViewModel
{
IEnumerable<ZipTable> Zips { get; set; }
IEnumerable<AgainCandidate> Candidates { get; set; }
}
Instantiate that in your action method and return that as your model. This would be my preferred approach.
2) Stash your two collections in the ViewData bag in your action method:
ViewData["Zips"] = queryZip.ToList();
ViewData["Candidates"] = queryCandidates.ToList();
return View(ViewData);
You can pull this data in your view like this:
#foreach (var zip in ViewData["Zips"] as IEnumerable<ZipTable>)
{
...
}

In MVC is it possible to override an editor template

is it possible to override an editor template?
I have DateTime fields in my model, which are used for arrival/departure dates - and these are rendered using the following EditorTemplate:
#model Nullable<System.DateTime>
#if ( Model.HasValue ) {
#Html.TextBox( "" , String.Format( "{0:dd/MM/yyyy}" , Model.Value ) , new { #class = "datepicker span2" } )
}
else {
#Html.TextBox( "" , String.Format( "{0:dd/MM/yyyy}" , DateTime.Now ) , new { #class = "datepicker span2" } )
}
...which will format datetime fields eg: 01/08/2012
However, I also want to show, in another field, the date AND time a booking was made eg:
22/07/2012 08:23
My model is:
public DateTime Arrival { get; set; }
public DateTime Departure { get; set; }
public DateTime TimeBooked { get; set; }
I would like TimeBooked to show time as well - but the Editor Template obviously just shows the date.
Can this be overridden? Or is there another way of doing this?
Thank you,
Mark
You can add a different named editor which shows time also and use an overload of EditorFor, which accepts template name as second parameter, like:
EditorFor(m=>m.TimeBooked, "DateWithTimeTemplate")
MSDN help
You can by using the UIHintAttribute attribute.
You can decorate the TimeBooked property with this attribute so MVC will know which editor to use.
Yes, you can do that by adding the hh:mm placeholder..
String.Format("{0:d/M/yyyy HH:mm:ss}", DateTime.Now)
For more examples, see here..

Resources