How to assign and use variable in MVC Razor View - asp.net-mvc

I've identified several of my views that require some simple logic, for example to add a class to a set of controls created with #Html helpers. I've tried several different ways, but they either throw errors in the View or just don't work.
A simple example:
Assign variable:
#if( condition )
{
var _disabled = "disabled";
}
#Html.CheckBoxFor(m => m.Test, new { #class = "form-control " + #_disabled })
Or:
#if( condition )
{
var _checked = "checked";
}
#Html.CheckBoxFor(m => m.Test, new { #checked = #_checked })
Of course, these doesn't work. I'm just trying to eliminate a bunch of #if conditions in my Views, but I have other lightweight logic uses for using variables. My problem might be more of how to use a variable in this way than actually assigning it?

It would seem that you're understanding razor fine.
The problem with your code seems to be that you're using a variable out of scope. You can't define a variable inside an if statement, and then use it outside, because the compiler won't know for sure that the variable outside actually exists.
I would suggest the following:
#{
var thing = "something";//variable defined outside of if block. you could just say String something; without initializing as well.
if(condition){
thing = "something else";
}
}
#Html.Raw(thing);//or whatever
As a side note, (in my opinion) it's better to do stuff in the controllers when you can, rather than the views. But if things make more sense in the views, just keep them there. (-:
Hope this helps.

Try this;
#{
var disabled = string.Empty;
if (true)
{
disabled = "disabled";
}
}
#Html.CheckBoxFor(m => m.RememberMe, new { #class = "form-control " + disabled })
Thanks!

Related

How to declare a variable in mvc view with razor to have html atribute class

I want to display a text with 2 links inside the text in MVC view!
The text link are dynamic from server side and looks like this in controller:
Model.Message = "You have used up all your credits for this month (see your credit balance {FirstLink}). You can buy credits {SecondLink}";
In view I have something like this
#{
var messageToShow = #Model.Message;
var newText = Html.ActionLink(Model.LinkText, Model.LinkAction, Model.LinkController, Model.LinkRouteValues).ToString();
var link = Html.ActionLink(Model.SecondLinkText, Model.SecondLinkAction, Model.SecondLinkController, Model.LinkRouteValues).ToString();
}
#if (!string.IsNullOrEmpty(Model.LinkText))
{
messageToShow = messageToShow.Replace("{FirstLink}", newText);
}
#if (!string.IsNullOrEmpty(Model.SecondLinkText))
{
messageToShow = messageToShow.Replace("{SecondLink}", link);
}[![enter image description here][1]][1]
#Html.Raw(messageToShow)
This is working like it is but I have to add the class to it like this
#Html.ActionLink(Model.SecondLinkText, Model.SecondLinkAction, Model.SecondLinkController, Model.LinkRouteValues, new { #class = "link" })
When adding the ,new{ #class = "link"} I got syntax error since the closing } is badly interpreted by razor engine.
Can you help out or maybe suggest a better solution?
Thanks
In order to solve the syntax error, your view model would need to include a property for the html attributes, either
public IDictionary<string, object> LinkAttributeValues { get; set; }
if LinkRouteValues is typeof RouteValueDictionary, or
public object LinkAttributeValues { get; set; }
if LinkRouteValues is typeof object
And then you code becomes
Html.ActionLink(Model.SecondLinkText, Model.SecondLinkAction,
Model.SecondLinkController, Model.LinkRouteValues, Model.LinkAttributeValues)
Note that both your #if (!string.IsNullOrEmpty(Model....)) lines so of code are pointless since if either LinkText or SecondLinkText were null or an empty string, the previous Html.ActionLink(..) lines of code would have thrown an exception.
One option would be to simply use
<span>You have used up all your credits for this month (see your credit balance</span>
#Html.ActionLink(Model.LinkText, Model.LinkAction, Model.LinkController, Model.LinkRouteValues, new { #class = "link" })
<span>). You can buy credits</span>
#Html.ActionLink(Model.SecondLinkText, Model.SecondLinkAction, Model.SecondLinkController, Model.LinkRouteValues, new { #class = "link" })
or if you want to set the message text in the controller, you could have 2 properties, say string Message and string Message2 and use <span>#Model.Message1</span>....
You don't need to prefix an '#' before the ActionLink when you're inside a code block. Remove that and I'm sure the syntax error will disappear.

Change the Telerik DateTimePicker element ID, but keep the name

I have a ASP.NET MVC page with multiple forms on it, where each form edits a different instance of the same class. Each form also includes a Telerik DateTimePicker control. What I want is to have the element IDs change, but not the element name. So I have something like this:
string idString = string.Format("MyObject{0}", Model.ID)
#Html.Telerik().DatePickerFor(m => m.SomeDate).HtmlAttributes(new { id = idString + "-SomeDate" })
Now this works mostly fine, except that at the bottom of the page, the auto-generated Javascript that Telerik puts in looks like:
jQuery('#SomeDate').tDateTimePicker({
format:'M/d/yyyy h:mm tt',
minValue:new Date(1899,11,31,0,0,0,0),
maxValue:new Date(2100,0,1,0,0,0,0),
startTimeValue:new Date(2013,3,22,0,0,0,0),
endTimeValue:new Date(2013,3,22,0,0,0,0),
interval:30,
selectedValue:new Date(2013,3,22,11,9,1,180)
});
Note that my idString value didn't get put in. I can try:
#Html.Telerik().DatePickerFor(m => m.SomeDate).Name(idString + "SomeDate")
And this makes the auto-generated Javascript correct (jQuery('#MyObject123-SomeDate')) but now the element name is wrong, so TryUpdateModel fails.
How can I get this to work? Thanks.
EDIT: I hacked this using the following Javascript, but this is a kludgy way to fix this.
$(function () {
window.setTimeout(function () {
for (var i = 0; i < document.getElementsByTagName("input").length; i++) {
var obj = document.getElementsByTagName("input")[i];
if (obj.id.indexOf("SomeDate") == -1)
continue;
obj.name = "SomeDate";
}
}, 150)
});
The solution was to use the Telerik object's .InputHtmlAttributes method.
#Html.Telerik().DatePickerFor(m => m.SomeDate).InputHtmlAttributes(new { id = idString + "-SomeDate" })

Can a Ninject binding be based on a URL/route value?

I have a single controller that I want to use for CRUD operations on two different entities which implement the same interface. I'd like for Ninject to give it a different repository based on a query string value in the URL (or maybe a different URL, routed to the same controller). Is this possible? How can I do it?
That's usually a design smell but you could define the binding like this:
kernel.Bind<IRepo>().ToMethod(ctx =>
{
var a = HttpContext.Current.Request["a"];
if (a == "b")
{
return new RepoA();
}
return new RepoB();
}).InRequestScope();
The following worked for me, Getting A Specific value from a route
kernel.Bind<IRepo>().ToMethod(ctx =>
{
var a = HttpContext.Current.Request.RequestContext.RouteData.Values["RouteDateValue"]
if (a != null)
{
return new RepoA(a);
}
return new RepoB();
})

How can I avoid duplicating this grid config code?

I have the following code that is used in a Razor view to configure grid settings for a DevExpress GridView MVC extension. All is good with the code, but now I wish to do data exports from the grid, which require the same configuration code on the 'server', i.e. upstream of the view. I could quite easily do this and provide a GridSettings property on my view model, if it were not for the required access to the WebViewPage<TModel>.ViewContext property.
Right now I am using a really ugly workaround and passing ViewContext back into the controller from the view; the controller then builds the grid settings. Needless to say the view calling a method on the controller is rather smelly.
settings.Columns.Add(column =>
{
column.Caption = "#";
column.SetDataItemTemplateContent(c =>
{
ViewContext.Writer.Write(
Html.ActionLink("Edit", "Edit", new {id = DataBinder.Eval(c.DataItem, "Id")}) + "&nbsp" +
Html.ActionLink("Delete", "Delete", new {id = DataBinder.Eval(c.DataItem, "Id")},
new {onclick = "return confirm('Do you really want to delete this record? [Just say no!]')"})
);
});
column.SetHeaderTemplateContent(c => ViewContext.Writer.Write(Html.ActionLink("New", "Create")));
column.Settings.AllowDragDrop = DefaultBoolean.False;
column.Settings.AllowSort = DefaultBoolean.False;
column.Width = 70;
});
settings.Columns.Add("RefNum", "Emp. No.");
In general, it is necessary to have only the "Name" property of the exported GridViewSettings object on both the PartialView and Controller sides.
The GridView's PartialView should also be wrapped with a form.
See this example in the DX code library and this thread.
It is possible to specify shared GridViewSettings on the Controller side within a static object (like in this demo).

Help With Embedded BaseFormDoctrine Forms

I have the following code blocks:
class MerchantStoreForm extends sfForm
{
public function configure()
{
$this->disableCSRFProtection();
$this->setWidgets(array(
'brand_id' => new sfWidgetFormDoctrineChoice(array('label'=> 'Store Brand','model'=>'Brand','add_empty'=>'-Select Brand-','method'=>'getName','key_method'=>'getId','order_by'=>array('name','asc'))),
'newbrand' => new sfWidgetFormInputCheckbox(array('label' => 'New'),array('value'=>'Y'))
));
$this->setValidators(array(
'newbrand' => new sfValidatorString(array('required'=>false)),
'brand_id' => new sfValidatorDoctrineChoice(array('model'=>'Brand'))
));
$brand = new Brand();
$brand_form = new BrandForm();
$brand_form->widgetSchema['name']->setAttribute('style','display:none');
$this->embedForm('brand', $brand_form);
$this->getWidgetSchema()->setNameFormat('store[%s]');
}
public function execute()
{
$form_values = $this->getValues();
if($form_values['newbrand'])
{
$brand_form = $this->getEmbeddedForm('brand');
$brand_form->save();
$brand = $brand_form->getObject();
}
else
{
$brand = doctrine::getTable('Brand')->findOneById($form_values['brand_id']);
}
return $brand->getId();
}
}
Two questions:
1) The magic of $brand_form->save() doesn't work for me. I get a 500 Internal Server Error sfValidatorErrorSchema error pointing to the following piece of code in my symfony generated BaseBrandForm.class.php:
...
$this->widgetSchema->setNameFormat('brand[%s]');
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
...
This works instead in replacement though:
$brand_form->updateObject($form_values['brand']);
$brand_form->getObject()->save();
Why is this?
2) Why do I get an undefined method error while calling getter method on the object of the BaseFormDoctrine embedded form:
return $brand->getId();
Thanks in advance for your help.
Sharmil
1) BrandForm throws an exception because it doesn't have any values. Classes that extend sfFormObject don't play nicely when embedded directly into non object forms (like sfForm).
What is MerchantStoreForm doing? Depending on the situation, it should probably be extending sfFormObject or BrandForm should be the top level form. If this isn't possible, you'll have to write add a save method to MerchantStoreForm that calls updateObject and save. To better understand what's happening, go through the logic that takes place in sfFormObject - it's worth knowing especially if you're using embedded forms.
2) No clue here. I would see what $brand is actually an instance of. If it's a record and that record has an id field, there's no reason that shouldn't work.

Resources