Group radio buttons in foreach loop in MVC razor view? - asp.net-mvc

I have tried to group a set of radio buttons inside loop by providing additional html attribute in html help as below -
<ol class="Opt">
#foreach (var opt in quest.Options)
{
<li class="Opt">
#Html.RadioButtonFor(o => opt.Title, opt.Title, new { #name = "uniqueRadio"})
#Html.Label(opt.Title)
</li>
}
</ol>
However name attribute ot generated input html tag gets over-written by opt.Title for obvious reasons. MVC-4 uses name attribute for strongly typed model-binding when posting data.
How do I make radio button grouped together ?
EDIT: I replaced RadioButtonFor with RadioButton, as suggested below. But this way I miss-out model binding feature.
<ol class="Question">
#for (int j = 0; j < Model.Options.Count; j++)
{
<li class="Opt">
#Html.RadioButton("uniqueRadio", Model.Options[j].IsSelected, false)
#Model.Options[j].Title
</li>
}
</ol>

Use simple RadioButton
<ol class="Opt">
#foreach (var opt in quest.Options)
{
<li class="Opt">
#Html.RadioButton("uniqueRadio", opt.Title)
#Html.Label(opt.Title)
</li>
}
</ol

Related

Sitefinity Custom Fields for list widgets and how to use them in MVC view templates

I've added a Custom Field to the List Widget in Sitefinity 8.1, it's Type is Related data and it's Data type is Pages. The field name is LinkedPageUrl.
Works perfectly in the back end allowing me to select a page from system and store it against that particular List Item.
I can't find any place in Sitefinity's documentation that explains how I would programmatically use this field in a MVC based List.SimpleList.cshtml view template that I'm customizing.
I've seen this being used in the News widget where there is an associated Image for each News Article:
<img src="#Html.Raw(item.Fields.RelatedImg.Fields.MediaUrl)" class="img-responsive" />
But I don't get close to this because I don't have the slightest idea where to begin... What's the model structure, syntax, etc.
My objective is to change each list item rendered out into an anchor and the anchor should make use of this Related Data field's URL for it's Href property.
EDIT:
You can do something like this in the widget template:
#foreach (var item in Model.Items)
{
<h3 #Html.InlineEditingAttributes(Model.ProviderName, Model.ContentType.FullName, (Guid)item.Fields.Id)
#Html.InlineEditingFieldAttributes("Title", "ShortText")>
#item.Fields.Title
</h3>
<ul>
#foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
<li #Html.InlineEditingAttributes(Model.ProviderName, ((ListViewModel)item).ListItemViewModel.ContentType.FullName, (Guid)listItem.Fields.Id)>
<div #Html.InlineEditingFieldAttributes("Title", "ShortText")>
#listItem.Fields.Title
</div>
<div class="sfMultiRelatedItmsWrp">
<h2 class="sfrelatedItmTitle">Related pages</h2>
#foreach (var link in listItem.Fields.LinkedPageUrl)
{
var node = PageManager.GetManager().GetPageNode(link.Fields.Id);
var url = PageExtesnsions.GetFullUrl(node);
<div>#link.Fields.Title - #url</div>
}
</div>
</li>
}
</ul>
}
This is given that you selected that multiple pages can be selected per list item.
EDIT: Make sure to include the following namespaces
#model Telerik.Sitefinity.Frontend.Mvc.Models.ContentListViewModel
#using Telerik.Sitefinity.Frontend.Lists.Mvc.Models;
#using Telerik.Sitefinity.Frontend.Mvc.Helpers;
#using Telerik.Sitefinity.Modules.Pages;
EDIT2: If the custom field allows for only 1 page to be selected then it should look like this:
<div class="#Model.CssClass">
#foreach (var item in Model.Items)
{
<h3 #Html.InlineEditingAttributes(Model.ProviderName, Model.ContentType.FullName, (Guid)item.Fields.Id)
#Html.InlineEditingFieldAttributes("Title", "ShortText")>
#item.Fields.Title
</h3>
<ul>
#foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
<li #Html.InlineEditingAttributes(Model.ProviderName, ((ListViewModel)item).ListItemViewModel.ContentType.FullName, (Guid)listItem.Fields.Id)>
<div #Html.InlineEditingFieldAttributes("Title", "ShortText")>
#listItem.Fields.Title
</div>
<div class="sfMultiRelatedItmsWrp">
<h2 class="sfrelatedItmTitle">Related pages</h2>
#{
var node = PageManager.GetManager().GetPageNode(listItem.Fields.LinkedPageUrl.Fields.Id);
var url = PageExtesnsions.GetFullUrl(node);
}
<div>#listItem.Fields.Title - #url</div>
</div>
</li>
}
</ul>
}
A good starting point is this article

How can I save the order a list of hidden form inputs which represent an array in ASP.NET MVC?

I have a sortable list of items which are generated from an array property on a model. I want to use jquery UI sortable to reorder the items and save this order in my Action method.
Here is the code I am using to output the items:
#using(#Html.BeginForm("Save", "MyController", FormMethod.Post))
{
<input type="submit" value="Save"/>
#Html.HiddenFor(x=>x.Id)
<ul id="sortable2" class="connectedSortable">
#{
int count = 0;
}
#foreach(var item in Model.CollectionOfThings)
{
<li class="ui-state-default">
#Html.Hidden("Things[" + count + "].Id", item.Id)
#Html.Hidden("Things[" + count + "].Title", item.Title)
#item.Title
</li>
count++;
}
</ul>
}
When I receive the model in my action method the order is the same as when I started. I understand that this is because of the index but I can't figure out a way (without writing some custom javascript to update the name attribute of each hidden input) to have the items bound to the array in correct order.
Can anyone suggest a way this could be achieved? I can probably write a bit of Javascript to do it but I hoped I could do this purely with model binding.
I tried outputting the inputs like this:
#Html.Hidden("Things[].Id", item.Id)
However this just resulted in my collection being null.
I have discovered a blog post from Phil Haack which contained the answer.
By using arbitrary indexes in a seperate hidden input with the name of my collection + .Index, the model binder seems to handle it and maintain the order.
#using(#Html.BeginForm("Save", "MyController", FormMethod.Post))
{
<input type="submit" value="Save"/>
#Html.HiddenFor(x=>x.Id)
<ul id="sortable2" class="connectedSortable">
#{
int count = 0;
}
#foreach(var item in Model.CollectionOfThings)
{
<li class="ui-state-default">
#Html.Hidden("Things.Index", "item" + count)
#Html.Hidden("Things[item" + count + "].Id", item.Id)
#Html.Hidden("Things[item" + count + "].Title", item.Title)
#item.Title
</li>
count++;
}
</ul>
}
Easier solution for you can be to collect only Ids. I assume titles can be recreated on server side. In this case you can just define:
#Html.Hidden("ThingIds", item.Id)
and bind to
List<int> thingsIds

C# foreach within foreach, display 3 item in each item. carousel

I am using asp.net MVC 4 for my project, and I have a Model.
and I am using Bootstrap Carousel to show products for my Index Page (see the image below)
Now my question is: I want to show 3 Products in each slide item.
should I write a ViewModel for this?
<div class="carousel slide>
#for (int i = 0; i <= Model.Count()/3; i++ ) <!-- this works well, paging -->
{
<div class="item #if(i==0){<text>active</text>}">
#foreach(var well in Model)
{
<div class="span4">
<!-- some html here -->
</div>
}
</div>
}
</div>
Your inner foreach is iterating over the entire Model collection - you'll need to restrict it to just the relevant three items.
I'm guessing you want something like:
<div class="carousel slide>
#for (int i = 0; i <= Model.Count()/3; i++ ) <!-- this works well, paging -->
{
<div class="item #if(i==0){<text>active</text>}">
#foreach(var well in Model.Skip(i*3).Take(3))
{
<div class="span4">
<!-- some html here -->
</div>
}
</div>
}
</div>
One way to think about this problem is to split the original collection into groups for each 3 sequential elements. Fortunately, you can use the GroupBy LINQ method using the "element index divided by 3" as key. IMO, the advantage of this solution is that it expresses more clearly your intent and has better performance than reiterating the collection with Skip(x * 3).Take(3) in the inner loop.
<div class="carousel slide>
#foreach (var group in Model.Select((x, index) => new { element = x, index }).GroupBy(x => x.index / 3, x => x.element))
{
<div class="item #if( group.Key == 0) {<text>active</text>}">
#foreach(var well in group)
{
<div class="span4">
<!-- some html here -->
</div>
}
</div>
}
</div>
I would even change the model type to ILookup<int, TElement> and perform the grouping in the controller.

AngularJS Dynamic sum of list

I am using angularJS ontop of my application.
I have a basic example of a controller:
function OrderListCtrl($scope, $http) {
$http.get('/static/angular/app/phones/van1.json').success(function(data) {
$scope.van1 = data;
});
$http.get('/static/angular/app/phones/van2.json').success(function(data) {
$scope.van2 = data;
});
}
And a sample JSON entry
{
"id": "3",
"custName": "Mrs Smith",
"accountNumber": "416",
"orderNumber": "12348",
"orderWeight": "120.20"
},
My html looks like this:
<div id=1>
<h1>Van 1 - Total Weight = XXX </h1>
<ul class="sortdrag">
<li ng-repeat="van1 in van1" id="[[ van1.id ]]">
[[van1.custName]] [[van1.accountNumber]] [[van1.orderWeight]]
</li>
</ul>
</div>
Now, I want to get the total weight for every li item in the ul.
This WOULD be easy if the lists where static, however the lists are using jQuery-ui and I have multiple lists where the li items are dragged and dropped between each list. My question is, how can I have the XXX dynamically update to the value of all weights in each li in the ul, or more to the question can this even be done?
I dont really want to use an onDrop event as this will not work on the pre-populated lists, so ideally I would like to use code that takes its values from all van1.orderWeight values in the ul.
Any suggestions on the best way to approach this would be very much appreciated! And before anyone asks im using [[ and ]] as opposed to {{ and }} because I am using jinja2 templates.
UPDATE:
Ok to after reading the answer below have amended the original controller to:
function OrderListCtrl($scope, $http) {
$http.get('/static/angular/app/phones/van1.json').success(function(data) {
$scope.van1 = data;
// This part is easy, calcuate the sum of all weights from the JSON data
$scope.sumV1 = _.reduce(_.pluck($scope.van1, 'orderWeight'), function (m, w) {return m + w}, 0);
});
$scope.getVan1Weight = function(){
// here I try and write a function to calculate the dynamic weight
// of a van, which will update when items get dropped in/out of the ul
_.reduce(_.pluck($scope.van1, 'orderWeight'), function (m, w) {return m + w}, 0);
}
And my template
<div id="app" ng-controller="OrderListCtrl">
<div id=1>
<h1>Van 1 - Total Weight = [[getVan1Weight()]]
Starting Weight - [[sumV1]]</h1>
<ul class="sortdrag">
<li ng-repeat="van1 in van1" id="[[ van1.id ]]">
[[van1.custName]] [[van1.accountNumber]] [[van1.orderWeight]]
</li>
</ul>
</div>
Now im using the underscorejs libary to help perform the calculations, but I can only seem to get this to work using the initial data, and not to update when new orders are dragged in from another ul
That is pretty each to achieve in Angular. You have to write a function in your controller that does the calculation for you and interpolate that function in your view. Something like
<div id=1>
<h1>Van 1 - Total Weight = [[getVanWeight()]] </h1>
<ul class="sortdrag">
<li ng-repeat="van1 in vans" id="[[ van1.id ]]">
[[van1.custName]] [[van1.accountNumber]] [[van1.orderWeight]]
</li>
</ul>
</div>
Inside your controller you do :
$scope.getVanWeight = function(){
// write your logic for calculating van weight here.
}
Thanks to #ganaraj I used the guide found at
http://www.smartjava.org/content/drag-and-drop-angularjs-using-jquery-ui
I also replaced my underscore code with pure angularjs code
$scope.getVan1Weight = function(){
var sum = 0;
for( t=0; t < $scope.van1.length; t++) { sum += $scope.van1[t].orderWeight }
return sum.toFixed(2);;
}
At the beginning of my controller I also defined an empty array (to get overwritten later)
// Define an empty array
$scope.van1 = [];
As this stops any errors producing as the $http get takes a while to load and when you load a browser window the .length returns an error, so if you define an empty array it stops any errors. I could have tested to see if an array was valid and put some if clauses in, but my angularjs knowledge is very limited so this solution worked best for me.
Here's something very similar to your requirement with a solution that works nicely...
Markup...
<table class="table table-condensed table-striped">
<thead>
<tr>
<th>Pillar Name</th>
<th>Weight</th>
<th>Metrics</th>
<th> Actions</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="p in l.pillars">
<td>{{p.name}}</td>
<td>{{p.weight}}</td>
<td>{{p.metrics.length}}</td>
<td>
<a href="" data-ng-click="vm.editPillar(p)">
<i class="fa fa-pencil blue"></i>
</a>
<a href="" data-ng-click="vm.deletePillar(p, l)">
<i class="fa fa-times-circle red"></i>
</a>
</td>
</tr>
<tr>
<td><strong>Totals</strong></td>
<td><strong>{{l.pillars.summedWeight}}</strong></td>
<td></td>
<td></td>
</tr>
</tbody>
js, which gets called when i get pillars from the server or local cache...
function getSummedPillarWeight(pillars) {
var summedWeight = 0;
pillars.forEach(function (pillar) {
summedWeight = summedWeight + pillar.weight;
});
return pillars.summedWeight = summedWeight;
}

MVC 3/4 Razor Help needed

I need to create Menu for the master page. I've faced with following problem
<ul class="main_menu">
#foreach (var node in Model.Nodes)
{
int i = 1;
<li class="**HOW TO ADD HERE A CLASS like level+i.ToString()?????**">#Html.DisplayFor(m => node) |
#if (node.Children.Any()) {
<ul class="menuchild" style="display: none;">
<li>
#Html.DisplayFor(m => node.Children)
</li>
</ul>
}
</li>
}
</ul>
I need to create levels for the menu for Javascript , say level1 , level2 , level3 , how to combine strings inside Razor.
Thanks.
Enclose with #()
<li class="#("level" + i.ToString() )">
or
<li class="#string.Format("level{0}", i)">

Resources