I'm currently programming a modal to add some basic information to print an invoice with that information later on. The code is still messy but as soon as i figure out how to solve my problem, I'm going to smarten up the code a little bit.
I'm currently struggling in creating some input fields that are used to add or remove the items of the invoice. Currently it looks like that:
When I open that modal, I retrieve the OrderSpecifications (that's what I call these lines) from the DB and populate the input fields.
protected override void OnInitialized()
{
specs = nfzContext.OrderSpecifications.Where(x => x.FkOrderNumber == order.Id).ToList();
numberOfSpecLines = nfzContext.OrderSpecifications.Where(x => x.FkOrderNumber == order.Id).Count();
SetupSpeclines();
}
I have 5 input fields predefined, which are only hidden in case there are no specification lines already existing. If i press the + button, I show the a new line.
<div class="card-body">
<div class="form-group">
<div class="row">
<div class="col">
<input class="form-control" type="text" #bind="specification1.ItemName" hidden="#specLine1Disabled" placeholder="Zeile 1" />
</div>
</div>
<div class="row">
<div class="col">
<input class="form-control" type="text" #bind="specification2.ItemName" hidden="#specLine2Disabled" placeholder="Zeile 2" />
</div>
</div>
</div>
</div>
The SetupSpecline method grabs the existing speclines and adds a reference for each to one of the five specification1 ... specification5 variables:
void SetupSpeclines() {
if (numberOfSpecLines <= 1) {
specLine1Disabled = false;
if (numberOfSpecLines == 1) specification1 = specs.ElementAt(0);
numberOfVisibleSpecLines = 1;
}
else if (numberOfSpecLines == 2) {
specLine1Disabled = false;
specLine2Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
numberOfVisibleSpecLines = 2;
}
else if (numberOfSpecLines == 3) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
numberOfVisibleSpecLines = 3;
}
else if (numberOfSpecLines == 4) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specLine4Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
specification4 = specs.ElementAt(3);
numberOfVisibleSpecLines = 4;
}
else if (numberOfSpecLines == 5) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specLine4Disabled = false;
specLine5Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
specification4 = specs.ElementAt(3);
specification5 = specs.ElementAt(4);
numberOfVisibleSpecLines = 5;
}
}
This it the database model for OrderSpecification (ID = primary key):
namespace MyNamespace
{
public class OrderSpecification
{
public OrderSpecification();
public int Id { get; set; }
public int FkOrderNumber { get; set; }
public int SeqId { get; set; }
public string ItemName { get; set; }
public virtual Order FkOrderNumberNavigation { get; set; }
}
}
You can unhide (+) up to five inputs and enter some data. After you press the OK button, the routine starts to check if individual lines have a) altered (=ItemName changed), if new ones were added or if some were removed (=empty input):
void Confirm()
{
List<OrderSpecification> linesToAdd = new List<OrderSpecification>();
List<OrderSpecification> linesToRemove = new List<OrderSpecification>();
if (!string.IsNullOrEmpty(specification1.ItemName))
{
// Check if there is a spec at index 0
if (specs.ElementAtOrDefault(0) != null)
{
specs.ElementAtOrDefault(0).ItemName = specification1.ItemName; // Only itemName has changed
}
else
{ // Add new line
linesToAdd.Add(new OrderSpecification { FkOrderNumber = order.Id, ItemName = specification1.ItemName, SeqId = 1 });
}
}
else if (!string.IsNullOrEmpty(specification1.ItemName) && specs.ElementAtOrDefault(0) != null)
Now, while all that works just fine, I have trouble writing the new speclines to the database. For example, When i run
foreach (var spec in LinesToAdd)
{
nfzContext.Add(spec);
}
nfzContext.SaveChanges();
I get the error message
{"Cannot insert explicit value for identity column in table
'OrderSpecifications' when IDENTITY_INSERT is set to OFF."}
What I assume is that EF Core tries to add the new OrderSpecification with the ID=0, which is the standard value when creating a new OrderSpecification element. I need to tell EF Core to not write the ID as 0 but to let the database set the value by using auto_increment.
And what's odd is, although I have assigned the Primary Key to the ID field, when I scaffold, the key is not set in the modelbuilder:
modelBuilder.Entity<OrderSpecification>(entity =>
{
entity.ToTable("OrderSpecifications", "samnfz");
entity.Property(e => e.Id).HasColumnName("ID");
entity.Property(e => e.FkOrderNumber).HasColumnName("FK_OrderNumber");
entity.Property(e => e.ItemName).IsRequired();
entity.Property(e => e.SeqId).HasColumnName("SeqID");
entity.HasOne(d => d.FkOrderNumberNavigation)
.WithMany(p => p.OrderSpecifications)
.HasForeignKey(d => d.FkOrderNumber)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_OrderSpecifications_Orders");
});
Any idea?
Ugh, I think I have found the error. After analyzing the table structure in the modelbuilder, I recognized that the structure is not the same that I have in my database. So i scaffolded once again and the error is gone. obviously, I used model types that were not current and maybe the primary key was set to another attribute...
I have read hundreds of posts about this problem and I still can't find a solution.
Please help with this horrible mistery;
I would like to have different default values in my DropDownListFor. The "PartialViewList1 exists out of 4 items.
I want the DropDownListFor to select the id of the current item. (item.id)
But because of testing purposes I just filled in "3". And even that doesn't work.
The Models are filled correctly, I am able to add more code of the controller but that wouldn't add much. But please ask if you want me to.
And yes I know that it is better to make the SelectList in the controller, but first I want to make it work.
View:
#foreach (var item in Model.PartialViewList1)
{
<tr>
<td>Plaats: </td>
<td>#item.PlaceNumber</td>
<td>
#Html.DropDownListFor(x => x.PartialView.Id, new SelectList(Model.PartialViewList2, "Id", "Name", 3),
new { onchange = "this.form.submit();" })</td>
</tr>
}
Screen shot of the users view
I hope that maybe someone can use this for his or her problem.
With Stephen Mueke I have found the solution. The problem is that if "x => x.PartialView.Id" already has a value then the default value : "3" will be overriden by the Id.
And you can't generate multiple DropDownlistFor's while binding them to the same property.
My solution on my problem:
View:
#using (Html.BeginForm("_PartialSettingsDropDownList1", "Home")){
<table>
#for (int i = 0; i < Model.maxNumberOfViews; i++)
{
<tr>
<td>
Plaats #(i+1)
</td>
<td>
#Html.DropDownListFor(x => Model.PartialViewList[i].ID, new SelectList(Model.PartialViewList, "Id", "Name", Model.PartialViewList[i].ID), "select")
</td>
</tr>
}
</table>
#Html.HiddenFor(x => x.maxNumberOfViews)
<input class="submit" type="submit" value="Submit" />}
Controller:
[HttpGet]
public PartialViewResult _PartialSettingsDropDownList1()
{
PartialScreenViewModel viewModel = new PartialScreenViewModel();
viewModel.PartialViewList = homeModel.AllBoxViews(databaseRepository.PartialViews);
viewModel.maxNumberOfViews = viewModel.PartialViewList.Count();
return PartialView(viewModel);
}
[HttpPost]
public RedirectResult _PartialSettingsDropDownList1(PartialScreenViewModel viewModel)
{
for (int i = 0; i < viewModel.maxNumberOfViews; i++)
{
PartialView viewOnScreen = databaseRepository.PartialViews.FirstOrDefault(x => x.ID == viewModel.PartialViewList[i].ID);
databaseRepository.UpdatePartialView(viewOnScreen, i+1);
}
return new RedirectResult("Settings");
}
Model:
public List<PartialView> AllBoxViews(IEnumerable<PartialView> allViews)
{
List<PartialView> OnlyBoxViews = new List<PartialView>();
foreach (var item in allViews.Where(item => item.Type.Equals("box")))
{
OnlyBoxViews.Add(item);
}
return OnlyBoxViews;
}
ViewModel:
public class PartialScreenViewModel
{
public List<PartialView> PartialViewList { get; set; }
public int maxNumberOfViews { get; set; }
}
Result on screen: screenshot
The following works as it should. The problem is that i do not want to hardcode the AvailabilityID and the AvailabilityName
public ActionResult Create()
{
SelectList AvailabilityList = new SelectList(db.Availabilities, "AvailabilityID", "AvailabilityName");
ViewBag.AvailabilityList = AvailabilityList;
return View();
}
and here comes the view
#Html.DropDownListFor(model => model.Availability, (SelectList)ViewBag.AvailabilityList, new
{
#class = "red",
data_placeholder = "please choose"
})
How should i modify the code above?
I am 99% sure with a lambda expression, so i can also add an order by clause... but what about the other 1% ?
Thank you
A little extension (in a static class) like this could do the trick
public static IEnumerable<SelectListItem> ToSelectListItem<T, TValue, TText>(
this IEnumerable<T> enumerable,
Func<T, TText> text,
Func<T, TValue> value,
)
{
return enumerable.Select(item => new SelectListItem
{
Text = text(item).ToString(),
Value = value(item).ToString(),
}).AsEnumerable();
usage :
//you can add an OrderBy if needed
var AvailabilityList = db.Availabilities.ToList().ToSelectListItem(m => m.AvailabilityName, m => m.AvailabilityId);
of course, it's an IEnumerable<SelectListItem> now, not a SelectList, but both can be used with a DropDownListFor
What is the best practice for this:
I have a list of partials on one page. Each page has a form on it to save the data of the partial.
I do this like this on the main page:
#foreach (var taak in Model)
{
#Html.Action("DetailTaak", "Checklist", new { trouwTaakId = taak.Id })
}
Then the controller is this (where the data is filled):
public ActionResult DetailTaak(int trouwTaakId)
{
DTO.Trouw.TrouwTaak viewModel;
viewModel = _themaService.GetTrouwTaakByTrouwTaakId(trouwTaakId);
return View(viewModel);
}
The page gets build and the list is completed. Now when I want to save a partial using this code:
#using (Html.BeginForm("DetailTaak", "Checklist", FormMethod.Post, new { #class = "form-horizontal col-md-12", role = "form", id = #Model.Id }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
...
}
It works but what do I do so the mainpage doesn't have to be reloaded ? This is the post code:
[HttpPost]
public ActionResult DetailTaak(DTO.Trouw.TrouwTaak model)
{
if (ModelState.IsValid)
{
ViewBag.SaveSuccess = "Je instellingen zijn opgeslagen";
}
return View("DetailTaak", model);
}
With this post code I go to the DetailTaak page instead of staying on the main page and just updating the partial.
I am doing something wrong but I don't know which way to go.
kind regards
First, I cant believe that anyone in 2011 is still using RSS 1.0, guess you really learn something new. Well I'm trying to parse their feed and put the content on my clients site (I got permissions so no law breaking here). As you can imagine my first attempt failed miserably (was wrting code for 2.0) so I went back to the drawing board and here's what I've come up with.
RssController
public virtual ActionResult Index()
{
List<RssFeedItem> rssList = new List<RssFeedItem>();
XmlDocument doc = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
manager.AddNamespace("rss", "http://purl.org/rss/1.0/");
XmlTextReader reader = new XmlTextReader("http://wdfw.wa.gov/news/newsrss.php");
doc.Load(reader);
XmlNodeList nodes = doc.SelectNodes("/rdf:RDF//rss:item",manager);
foreach(XmlNode node in nodes)
{
XmlNodeList aboutNode = node.SelectNodes("rss:about", manager);
XmlNodeList titleNode = node.SelectNodes("rss:title", manager);
XmlNodeList linkNode = node.SelectNodes("rss:link", manager);
var item = new RssFeedItem
{
Link = linkNode.Count == 0 ? "" : linkNode[0].InnerText,
Title = titleNode.Count == 0 ? "" : titleNode[0].InnerText,
About = aboutNode.Count == 0 ? "" : aboutNode[0].InnerText
};
rssList.Add(item);
}
return View(rssList);
}
I'm attempting to do this utilizing a partial view (ascs) and that looks like this
Index.aspx
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<GodsCreationTaxidermy.Models.RssFeedItem>" %>
<%
foreach (RssFeedItem item in (IEnumerable<RssFeedItem>)ViewData.Model)
{
Response.Write(string.Format("<div id={0}><a href={1} target=\"_blank\" /> <strong>{2}</strong></div>",
Model.About.Truncate(5), Model.Link, Model.Title.Truncate(25)));
} %>
Then I try RenderPartial in mySite.Master
<% Html.RenderPartial("Index");%>
The problem is that the site never even loads, or even gives some kind of error, it just sits tere with FF's litte loading icon spinning.
EDIT
Well I've made some major changes to my code from earlier, and same result, no error and it doesnt load the site even (just sits & spins). Here's the code from the Controller
[MoveFormsScript]
[CanonicalUrlAttribute("Rss")]
public virtual ActionResult Index()
{
return View(new RssList());
}
Now the code from RssList
[UIHint("Feeds")]
public SelectList Feeds { get; private set; }
[Required(ErrorMessage = "Rss Feeduired")]
public string Feed { get; set; }
public RssList()
{
this.Feeds = GetRssFeed(null);
}
public SelectList GetRssFeed(string selectedValue)
{
List<RssFeedItem> rssList = new List<RssFeedItem>();
XmlDocument doc = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("rdf", "http://www.w3.org/1 999/02/22-rdf-syntax-ns#");
manager.AddNamespace("rss", "http://purl.org/rss/1.0/");
XmlTextReader reader = new XmlTextReader("http://wdfw.wa.gov/news/newsrss.php");
doc.Load(reader);
XmlNodeList nodes = doc.SelectNodes("/rdf:RDF//rss:item", manager);
foreach (XmlNode node in nodes)
{
XmlNodeList aboutNode = node.SelectNodes("rss:about", manager);
XmlNodeList titleNode = node.SelectNodes("rss:title", manager);
XmlNodeList linkNode = node.SelectNodes("rss:link", manager);
var item = new RssFeedItem
{
Link = linkNode.Count == 0 ? "" : linkNode[0].InnerText,
Title = titleNode.Count == 0 ? "" : titleNode[0].InnerText,
About = aboutNode.Count == 0 ? "" : aboutNode[0].InnerText
};
rssList.Add(item);
}
return new SelectList(rssList, "Link", "Title", selectedValue);
}
And finally my partial view
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<GodsCreationTaxidermy.Helpers.BusinessDTO.RssList>" %>
<%
foreach (var item in (IEnumerable<RssList>)ViewData.Model)
{
Response.Write(string.Format("<div id=\"{0}\"><a href=\"{1}\" target=\"_blank\" /> <strong>{2}</strong></div>",
item.Feed[0].ToString().Truncate(10), item.Feed[1], item.Feed[2].ToString().Truncate(100)));
} %>
Can anyone help me?
Change the instantiation of the XmlNodeList is the RssList class to:
XmlNodeList nodes = doc.SelectNodes("//rss:item[./rss:link]", manager);
Then change your ViewUserControl to this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %><ul>
<%
RssList viewModel = ViewData.Model as RssList;
if (viewModel.Feeds.Count() > 0)
{
foreach (SelectListItem item in viewModel.Feeds)
{ %>
<li>
<%
Response.Write(String.Format("<a href='{0}' target='_blank'>{1}</a>", item.Value, item.Text));
}%>
</li>
<%
}
%></ul>
Seems to work for me.
There are a few problems I see here. Your control is expecting a single RssList, the Controller is returning a select list, and your foreach is enumerating over what it thinks is an IEnumerable<RssList>. Also, you're doing manual response.writes in the partial view. The markup would be cleaner if you didn't do that.
Let's start with the RssList class first. It looks like your first approach was actually what you wanted, the problem was just what you were doing in the partial view.
public class RssList
{
[UIHint("Feeds")]
public IEnumerable<RssFeedItem> Feeds { get; private set; }
[Required(ErrorMessage = "Rss Feed Required")]
public string Feed { get; set; }
public RssList()
{
this.Feeds = GetRssFeed(null);
}
public IEnumerable<RssFeedItem> GetRssFeed(string selectedValue)
{
List<RssFeedItem> rssList = new List<RssFeedItem>();
XmlDocument doc = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("rdf", "http://www.w3.org/1 999/02/22-rdf-syntax-ns#");
manager.AddNamespace("rss", "http://purl.org/rss/1.0/");
XmlTextReader reader = new XmlTextReader("http://wdfw.wa.gov/news/newsrss.php");
doc.Load(reader);
XmlNodeList nodes = doc.SelectNodes(
"/rdf:RDF//rss:item[./rss:link./rss:title./rss:about]", manager);
foreach (XmlNode node in nodes)
{
XmlNodeList aboutNode = node.SelectNodes("rss:about", manager);
XmlNodeList titleNode = node.SelectNodes("rss:title", manager);
XmlNodeList linkNode = node.SelectNodes("rss:link", manager);
var rssItem = new RssFeedItem
{
Link = linkNode.Count == 0 ? "" : linkNode[0].InnerText,
Title = titleNode.Count == 0 ? "" : titleNode[0].InnerText,
About = aboutNode.Count == 0 ? "" : aboutNode[0].InnerText
};
rssList.Add(rssItem);
}
return rssList;
}
}
Now instead of a SelectList, we're returning an IEnumerable<RssFeedItem>. It's preferable not to manipulate the UI from the code if possible. So let's see if we need to work any magic on the controller. The only thing I see there is that you can exclude "Index" from the View function (it's implied because that is the name of the controller operation.
return PartialView(viewModel);
Now on to the view...let's see if we can make that look better
<%# Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<GodsCreationTaxidermy.Helpers.BusinessDTO.RssList>" %>
<%
foreach (var rssItem in ViewData.Model.Feeds)
{
%>
<div id="<%=rssItem.Title%>">
<a href="<%=rssItem.Link%>" target="_blank">
<strong><%=rssItem.Title%></strong>
</a>
<%
}
%>
There I think that should do it for you...let me know if you run into any problems.
I'm not really familiar with the System.Web.Mvc.SelectList class much less the namespace, but I noticed your using a string for the selectedValue parameter. Should it be an RssFeedItem object instead?
[edit]
Ran your xml code section through some powershell hurdles and here's what I get.
$doc = New-Object Xml.XmlDocument;
$manager = New-Object Xml.XmlNamespaceManager $doc.NameTable;
$manager.AddNamespace("rdf", "http://www.w3.org/1 999/02/22-rdf-syntax-ns#");
$manager.AddNamespace("rss", "http://purl.org/rss/1.0/");
$reader = New-Object Xml.XmlTextReader("http://wdfw.wa.gov/news/newsrss.php");
$doc.Load($reader);
#doesn't work
"Doesn't work"
$doc.SelectNodes("//rss:item[./rss:link./rss:title./rss:about]", $manager) | measure | select count
#this is an invalid xpath query, there are no operators between the nodes specified in the [].
#Also, in the xml document we're looking at, there is no node named "about". "about" is an attibute to the "item" node.
#works
"Works"
$doc.SelectNodes("//rss:item[./rss:link and ./rss:title]", $manager) | measure | select count
#Even though we only have the "link" and "title" nodes in the [], everything is returned.
#That's because we're telling SelectNodes to return the "item" nodes themselves.
Can a mod merge this feed with this one MVC2 - Consume RSS feed with RDF and namespace http://www.w3.org/1999/02/22-rdf-syntax-ns#'. I forgot I had already asked
Made some more changes dor those who are trying to help me. Here's the controllers code
[MoveFormsScript]
[CanonicalUrlAttribute("Rss")]
public virtual ActionResult Index()
{
var viewModel = new RssList();
return PartialView("Index", viewModel);
}
Then I created a class (RssList), which is where the bulk of the work is done
RssList
[UIHint("Feeds")]
public SelectList Feeds { get; private set; }
[Required(ErrorMessage = "Rss Feed Required")]
public string Feed { get; set; }
public RssList()
{
this.Feeds = GetRssFeed(null);
}
public SelectList GetRssFeed(string selectedValue)
{
List<RssFeedItem> rssList = new List<RssFeedItem>();
XmlDocument doc = new XmlDocument();
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("rdf", "http://www.w3.org/1 999/02/22-rdf-syntax-ns#");
manager.AddNamespace("rss", "http://purl.org/rss/1.0/");
XmlTextReader reader = new XmlTextReader("http://wdfw.wa.gov/news/newsrss.php");
doc.Load(reader);
XmlNodeList nodes = doc.SelectNodes("/rdf:RDF//rss:item[./rss:link./rss:title./rss:about]", manager);
foreach (XmlNode node in nodes)
{
XmlNodeList aboutNode = node.SelectNodes("rss:about", manager);
XmlNodeList titleNode = node.SelectNodes("rss:title", manager);
XmlNodeList linkNode = node.SelectNodes("rss:link", manager);
var rssItem = new RssFeedItem
{
Link = linkNode.Count == 0 ? "" : linkNode[0].InnerText,
Title = titleNode.Count == 0 ? "" : titleNode[0].InnerText,
About = aboutNode.Count == 0 ? "" : aboutNode[0].InnerText
};
rssList.Add(rssItem);
}
return new SelectList(rssList, "Link", "Title", selectedValue);
}
This is the Index.ascx
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<GodsCreationTaxidermy.Helpers.BusinessDTO.RssList>" %>
<%
foreach (RssList rssItem in ViewData.Model)
{
Response.Write(string.Format("<div id=\"{0}\"><a href=\"{1}\" target=\"_blank\" /> <strong>{2}</strong></div>",
rssItem.Feed[0].ToString().Truncate(10), rssItem.Feed[1], rssItem.Feed[2].ToString().Truncate(100)));
} %>
And a normal call
<% Html.RenderPartial("Index");%>
}
FeedItemCass
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace GodsCreationTaxidermy.Models
{
public class RssFeedItem
{
public string Link { get; set; }
public string Title { get; set; }
public string About { get; set; }
}
}