Displaying model data in view, check for null value - asp.net-mvc-5

I'm not sure if this is possible in the view or if I would somehow have to check for it in the controller but I have some values that are null and I'm trying to fill up a table but I would like a placeholder such as N/A to show up if there's no values.
In my controller I'm just return the model data of a basic linq query.
var model = from u in db.Users where u.Username == "Bob" select u;
In my view I'm just simply displaying the data in a table
<table class='table table-striped table-bordered table-responsive'>
<tbody>
<tr>
<td>#Html.DisplayFor(model => model.CallNo)</td>
</tr>
</tbody>
</table>

you can do something like this in your model:
[DisplayFormat(NullDisplayText = "PLACEHOLDER_VALUE")]
public string CallNo { get; set; }
Doing this you can just use
#Html.DisplayFor(model => model.CallNo)
as usual.

Related

a4j:support partial update before submit the form

I want to make quick search in the JSF page before I submit the form (partial update) , so I have two values, one is input text and I want the result show in the output text when the user enter the value in the input text. for example I want to search about the name of the user using the user id, so in the input text the user will enter the user id (e.g 2323) then the search will happens and this will render the output text with the name of this user(2323).
I use a4j:support in order to achieve this but nothing shown with me and there is no any error or exception.
this is my JsF page:
<tr>
<td>
<table>
<tr>
<td width="80px"><h:outputLabel
value="user id"></h:outputLabel></td>
<td width="5px"> </td>
<td><h:inputText id="secondIdNum" maxlength="6" style="width:240px"
value="#{ideaDetailsBean.addIdeaDto.secondId}">
<a4j:support event="onchanged" actionListener="#
{ideaDetailsBean.secondIdChange}"
reRender="secondNameId" />
</h:inputText></td>
<td width="15px"> </td>
<td width="80px"><h:outputLabel value="user name "></h:outputLabel></td>
<td width="5px"> </td>
<td><h:outputText id="secondNameId"
style="width:240px"
value="#{ideaDetailsBean.addIdeaDto.secondName}"></h:outputText>
</td>
</tr>
</table>
</td>
</tr>
in the backbean:
public void secondIdChange(ActionEvent actionEvent) {
if(addIdeaDto.getSecondId() != null){
addIdeaDto.setSecondName(getParticipantName(addIdeaDto.getSecondId()));
}
}
static String getParticipantName(String employeeId) {
IIMDelegate iimDelegate = new IIMDelegate();
UserInfoDto userInfoDto = new UserInfoDto();
iimDelegate.getParticipant(employeeId);
return userInfoDto.getUserName();
}
in the DAO:
public UserInfoDto getParticipant(String employeeId) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet searchResultSet = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(
"SELECT U_NAME FROM APPL_USER WHERE U_LOGIN = ?");
// Assign first value to first parameter
preparedStatement.setString(1, employeeId);
searchResultSet = preparedStatement.executeQuery();
return getParticipant(searchResultSet);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
searchResultSet.close();
preparedStatement.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
private UserInfoDto getParticipant(ResultSet searchResultSet) throws SQLException {
List<UserInfoDto> result = new ArrayList<UserInfoDto>();
UserInfoDto userInfoDto = null;
while (searchResultSet.next()) {
userInfoDto = new UserInfoDto();
userInfoDto.setUserName(searchResultSet.getString(1));
result.add(userInfoDto);
}
return result == null ? null : result.size() > 0 ? result.get(0) :null;
}
Any suggestion to achieve this in different way?

Loop of checkboxes to add objects to model list

I have a model (called plan) which one of its properties is a list (ICollection) of Exercises (which is another model):
public int Id { get; set; }
public virtual ICollection<Exercise> Exercises { get; set; }
So i tried to create a view that creates a plan and another view to add Exercises to the plan from exercises in the database.
So i did a loop that ranges all the exercises from the DB and for each one i added a check box with and id same as the id of the exercise and i thought i could do something with it but i tried so many things and ways and i couldn't even sent the input of the check boxes to the controller.
I must say that i'm kinda new with programming with mvc and i tried to look all over the internet and i didn't really know people who knows to program so this is really my last chance to solve it. Sorry if it was a long post or too easy for you to even comment but i really need this.
This is very specific for my project and what i stacked on was to sent the input to the controller but i'm open to different solutions cause i'm desperate.
public async Task<ActionResult> AddExercises(string id,int[] selectedExercises)
{
List<Exercise> list = new List<Exercise>();
foreach (int i in selectedExercises)
{
list.Add(db.Exercises.Find(i));
}
db.Plans.Find(id).Exercises = list;
await db.SaveChangesAsync();
return RedirectToAction("index");
}
I am sure its wrong and the view i tried is:
#using (Html.BeginForm("index", "Plans"))
{
#Html.AntiForgeryToken()
foreach (var i in Model.Exercises)
{
<table class="table">
<tr>
<td>#Html.DisplayFor(modelItem => i.Level)</td>
<td>#Html.DisplayFor(modelItem => i.Description)</td>
<td>#Html.DisplayFor(modelItem => i.MoreDescription)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = i.Id }) |
#Html.ActionLink("Details", "Details", new { id = i.Id }) |
<input type="checkbox" class="selectedObjects" id="i.id" /> |
</td>
</tr>
</table>
}
#Html.ActionLink("Finish", "AddExercises")
}
I use viewModel PlanExercise in this view
Your checkboxes do not have either a name attribute or a value attribute so there is nothing to submit. You html needs to be
<input type="checkbox" name="selectedExercises" value="#i.id" />
and then in order to submit the form, you need a submit button (remove #Html.ActionLink("Finish", "AddExercises"))
<input type="submit" value="Save" />
and the form needs to be (assuming the controller is FinishController)
#using (Html.BeginForm("AddExercises", "Finish"))
and the method needs to be marked with the [HttpPost] attribute.

RazorEngine - How to use a complex model view?

Anyone have experience working with a complex model and RazorEngine?
Working on generating HTML using RazorEngine version 3.7.3, but running into issues with the complex model view we have. It seems like we should be able to use the templates to get RazorEngine to discover the SubSample below, but have not discovered the proper way to tell RazorEngine about the associated cshtml file.
In the example below we are looking to use a shared template for the SubSample class using the SubSample.cshtml file. As can be seen from the results, the class namespace (ReportSample.SubSample) is displayed rather than an HTML row of data.
We have tried implementing an ITemplateManager, but Resolve() is never called with a key asking for the SubSample. Also tried AddTemplate() on the service, but still no joy.
Here is a simplified example model to illustrate the issue:
namespace ReportSample
{
public class SubSample
{
public string Name { get; set; }
public string Value { get; set; }
}
public class SampleModel
{
public SubSample SubSample { get; set; }
}
}
SampleModel.cshtml
#using ReportSample
#*#model ReportSample.SampleModel*#
<table style="width: 7.5in" align="center">
<tr>
<td align="center">
<h1>
Sample Report
</h1>
</td>
</tr>
<tr>
<td>
<table style="width: 100%">
<tr>
<td colspan="2">
<b>Name:</b> #Model.SubSample.Name
</td>
<td colspan="2">
<b>Value:</b> #Model.SubSample.Value
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="center">
<h1>
Sub-sample Data
</h1>
</td>
<td>
<table style="width: 100%">
#Model.SubSample
</table>
</td>
</tr>
</table>
SubSample.cshtml
#model ReportSample.SubSample
#using FSWebportal.Infrastructure.Mvc;
<tr class="observation-row">
<td class="observation-label">
#model.Name
</td>
<td class="observation-view">
#model.Value
</td>
</tr>
Basic RazorEngine calls:
private void html_Click(object sender, EventArgs e)
{
var gen = new RazorEngineGenerator();
var cshtmlTemplate = File.ReadAllText("Sample.cshtml");
var sample = new SampleModel() { SubSample = new SubSample() { Name = "name", Value = "value" } };
var html = gen.GenerateHtml(sample, cshtmlTemplate);
}
public string GenerateHtml<T>(T model, string cshtmlTemplate)
{
var config = new TemplateServiceConfiguration();
using (var service = RazorEngineService.Create(config))
{
return service.RunCompile(cshtmlTemplate, "", typeof(T), model);
}
}
Sample HTML Output:
Sample Report
Name: name
Value: value
Sub-sample Data
ReportSample.SubSample
I'm sorry but I don't think I fully understand your question but I have a small idea of what you are trying to do...
I think what you want are searching for are partial templates (using #Include)!
using RazorEngine;
using RazorEngine.Templating;
using System;
namespace TestRunnerHelper
{
public class SubModel
{
public string SubModelProperty { get; set; }
}
public class MyModel
{
public string ModelProperty { get; set; }
public SubModel SubModel { get; set; }
}
class Program
{
static void Main(string[] args)
{
var service = Engine.Razor;
// In this example I'm using the default configuration, but you should choose a different template manager: http://antaris.github.io/RazorEngine/TemplateManager.html
service.AddTemplate("part", #"my template");
// If you leave the second and third parameters out the current model will be used.
// If you leave the third we assume the template can be used for multiple types and use "dynamic".
// If the second parameter is null (which is default) the third parameter is ignored.
// To workaround in the case you want to specify type "dynamic" without specifying a model use Include("p", new object(), null)
service.AddTemplate("template", #"<h1>#Include(""part"", #Model.SubModel, typeof(TestRunnerHelper.SubModel))</h1>");
service.Compile("template", typeof(MyModel));
service.Compile("part", typeof(SubModel));
var result = service.Run("template", typeof(MyModel), new MyModel { ModelProperty = "model", SubModel = new SubModel { SubModelProperty = "submodel"} });
Console.WriteLine("Result is: {0}", result);
}
}
}
I have added documentation for this here: https://antaris.github.io/RazorEngine/LayoutAndPartial.html
However I think making #Model.SubSample work is possible as well, you can either change the SubSample property to be of type TemplateWriter or make the SubSample class implement IEncodedString. But I think you should consider partial templates first!

manipulate XML document with linq

I have the following xml that i need to transfom to an other form. I have a C# code that does it but it has a bug with is hard to track. I beleive Linq could offer a more error prone way to do this.
input xml:
<NewDataSet>
<Table>
<RoleId>5</RoleId>
<Code>DP</Code>
<Description>Process data</Description>
<Task>Validate indices</Task>
<TaskId>12</TaskId>
<Country>BE</Country>
<CountryId>3</CountryId>
</Table>
<Table>
<RoleId>5</RoleId>
<Code>DP</Code>
<Description>Process data</Description>
<Task>calculate indices</Task>
<TaskId>11</TaskId>
<Country>US</Country>
<CountryId>4</CountryId>
</Table>
<Table>
<RoleId>5</RoleId>
<Code>DP</Code>
<Description>Process data</Description>
<Task>Calculate indices</Task>
<TaskId>11</TaskId>
<Country>UK</Country>
<CountryId>5</CountryId>
</Table>
<Table>
<RoleId>1</RoleId>
<Code>DR</Code>
<Description>View data</Description>
<Task>View Reports</Task>
<TaskId>9</TaskId>
<Country>SC</Country>
<CountryId>17</CountryId>
</Table>
<Table>
<RoleId>1</RoleId>
<Code>DR</Code>
<Description>View data</Description>
<Task>View Basics</Task>
<TaskId>10</TaskId>
<Country>SC</Country>
<CountryId>17</CountryId>
</Table>
<Table>
<RoleId>1</RoleId>
<Code>DR</Code>
<Description>View data</Description>
<Task>Download data</Task>
<TaskId>11</TaskId>
<Country>FR</Country>
<CountryId>15</CountryId>
</Table>
</NewDataSet>
and the output that i need is as follow:
<NewDataSet>
<Table>
<RoleId>5</RoleId>
<Code>DP</Code>
<Description>Process data</Description>
<Task>Validate indices,Calculate indices,</Task>
<TaskId>12,11</TaskId>
<Country>BE,US,UK</Country>
<CountryId>3,4,5</CountryId>
</Table>
<Table>
<RoleId>1</RoleId>
<Code>DR</Code>
<Description>Process data from commercial fisheries</Description>
<Task>View Reports,View Basics,View data</Task>
<TaskId>9,10,11</TaskId>
<Country>SC,FR</Country>
<CountryId>17,15</CountryId>
</Table>
</NewDataSet>
As you can see, the elements are group by RoleId, Code and Description.
I have created a custum object to project the xml element to
public class Table
{
public int RoleId {get;set;}
public string Code {get;set;}
public string Description {get;set;}
public string Task {get;set;}
public int TaskId {get;set;}
public string Country {get;set;}
public int CountryId {get;set;}
}
The idea is then to use this list of custum object to recreate an xml document. But i was thinking there could be a more straigforward way. without the need to use the custum object list.
The rest of the element are simply concatenated. I hope someone have an idea sugestion of how this could be achieved using Linq to XML.
many thanks in advance
var doc = XDocument.Load("Input.txt");
var tables = from t in doc.Root.Elements("Table")
select new Table
{
RoleId = (int)t.Element("RoleId"),
Code = (string)t.Element("Code"),
Description = (string)t.Element("Description"),
Task = (string)t.Element("Task"),
TaskId = (int)t.Element("TaskId"),
Country = (string)t.Element("Country"),
CountryId = (int)t.Element("CountryId")
};
var groups = tables.GroupBy(x => new { x.RoleId, x.Code, x.Description });
var resultDoc = new XDocument(
new XElement("NewDataSet",
from g in groups
select new XElement("Table",
new XElement("RoleID", g.Key.RoleId),
new XElement("Code", g.Key.Code),
new XElement("Description", g.Key.Description),
new XElement("Task", string.Join(",", g.Select(x => x.Task))),
new XElement("TaskId", string.Join(",", g.Select(x => x.TaskId.ToString()))),
new XElement("Country", string.Join(",", g.Select(x => x.Country))),
new XElement("CountryId", string.Join(",", g.Select(x => x.CountryId.ToString()))))));
It's fully LINQ to XML solution, although you should consider changing the parsing part with XML Serialization.
Result XML:
<NewDataSet>
<Table>
<RoleID>5</RoleID>
<Code>DP</Code>
<Description>Process data</Description>
<Task>Validate indices,calculate indices,Calculate indices</Task>
<TaskId>12,11,11</TaskId>
<Country>BE,US,UK</Country>
<CountryId>3,4,5</CountryId>
</Table>
<Table>
<RoleID>1</RoleID>
<Code>Data Reader</Code>
<Description>View data</Description>
<Task>View Reports,View Basics,Download data</Task>
<TaskId>9,10,11</TaskId>
<Country>SC,SC,FR</Country>
<CountryId>17,17,15</CountryId>
</Table>
</NewDataSet>

Viewmodel IEnumerable property is empty

I'm in the middle of making an ASP .NET MVC4 based app. I'm a complete newb in that field. The idea is quite simple - have a some members in DB, show them listed, select desired ones via check boxes and redirect to some other controller which would do something with the previously selected members.
Problem is passing the list of members from View to the Controller. I've thought it would work with ViewModel. It certainly works from Controller to the View, but not the other way.
My ViewModel:
public class MembersViewModel
{
public IEnumerable<Directory_MVC.Models.Member> MembersEnum { get; set; }
public string Test { get; set; }
}
Snippet of my Controller:
public class MembersController : Controller
{
private MainDBContext db = new MainDBContext();
public ActionResult Index()
{
var model = new Directory_MVC.ViewModels.MembersViewModel();
// populating from DB
model.MembersEnum = db.Members.Include(m => m.Group).Include(m => m.Mother).Include(m => m.Father);
model.Test = "abc";
return View(model);
}
[HttpPost]
public ActionResult GoToSendEmail(Directory_MVC.ViewModels.MembersViewModel returnedStruct)
{
if (ModelState.IsValid)
{
// it is valid here
return Redirect("http:\\google.com");
}
}
Snippet of my View:
#model Directory_MVC.ViewModels.MembersViewModel
#{
ViewBag.Title = "Members listing";
var lineCount = 0;
string lineStyle;
}
#using (Html.BeginForm("GoToSendEmail", "Members", FormMethod.Post))
{
<table>
#foreach (var item in Model.MembersEnum)
{
lineCount++;
// set styling
if (lineCount % 2 == 1)
{
lineStyle = "odd-line";
}
else
{
lineStyle = "even-line";
}
<tr class="#lineStyle">
<td>
#Html.EditorFor(modelItem => item.Selected)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mother.FirstName) #Html.DisplayFor(modelItem => item.Mother.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Father.FirstName) #Html.DisplayFor(modelItem => item.Father.LastName)
</td>
<!-- other print-outs but not all properties of Member or Mother/father are printed -->
</tr>
}
</table>
<input type="submit" value="Send E-mail" />
}
The data are shown OK in the View. However, when I submit that form the returnedStruct.MembersEnum and Test string are both null in the Controller's method GoToSendEmail.
Is there a mistake or is there another possible way how to pass that members structure and check their Selected property?
Model binding to a collection works a little differently. Each item has to have an identifier so that inputs don't all have the same name. I've answered a similar question here.
#for (int i = 0; i < Model.MembersEnum.Count(); i++)
{
#Html.EditorFor(modelItem => modelItem.MembersEnum[i].FirstName)
}
...which should render something like...
<input type="text" name="MembersEnum[0].FirstName" value="" />
<input type="text" name="MembersEnum[1].FirstName" value="" />
<input type="text" name="MembersEnum[2].FirstName" value="" />
...which should then populate the collection in your ViewModel when picked up by the controller...
public ActionResult GoToSendEmail(ViewModels.MembersViewModel model)
As mentioned in the other answer, I'd have a look at some related articles from Scott Hansleman and Phil Haack.
You also mentioned that your string called Test is null when you submit to your POST action. You haven't added a field for this property anywhere within your form, so there's nothing for the model binder to bind to. If you add a field for it within your form then you should see the value in the POST action:
#Html.EditorFor(modelItem => modelItem.Test)
Html.BeginCollectionItem() helper did the job - BeginCollectionItem.

Resources