I am trying to get my head around knockout mvc framework. I am looking at the sample of a shopping cart and trying to figure out:
How to calculate total cost
Where to add client side business rules (such as discounts and vouchers)
To calculate subtotal the code reads
#using (lines.If(m => m.ProductId != -1))
{
using (var product = lines.With(m => ko.Model.DataBase[m.CategoryId].Products[m.ProductId]))
{
#product.Html.Span(m => "\\$" + m.Price)
}
}
When I try to get the total from there I usually end up with a compiler exception or NullReferenceException in run time. For example
#using (lines.If(m => m.ProductId != -1))
{
using (var product = lines.With(m => ko.Model.Categories[m.CategoryId].Products[m.ProductId]))
{
#product.Html.Span(m => "\\$" + (lines.Model.Quantity * m.Price))
#{double total = lines.Model.Quantity * m.Price;}
}
}
Gives me
Compiler Error Message: CS1501: No overload for method 'Write' takes 0
arguments
Seems like I am doing it wrong. Would anyone point me in a right direction?
Have you tried removing the # symbol from the start of each line? I'm sure once you open a razor code block, you don't need to keep prepending every line with #. Also, not sure why the 'double total' line is wrapped in {}?
#using (var product = lines.With(m => ko.Model.Categories[m.CategoryId].Products[m.ProductId]))
{
product.Html.Span(m => "\\$" + (lines.Model.Quantity * m.Price));
double total = lines.Model.Quantity * m.Price;
}
Related
I have an MVC5 View where I am using the Grid.MVC component (https://gridmvc.codeplex.com/). This allows me to easily display data from my Oracle DB and has out of the box functionality for Sorting/Filtering each Data Column. What I am trying to implement now is a Wildcard Search across all fields in my grid. For example, if I search the number "2" I'd like to return all records that contain a "2" be they string, decimal, or DateTime.
The filter capability on this grid performs filtering (for individual columns) partially by modifying the URL (http://homeURL/?grid-filter=Location.DEPT__1__accounting) such as 1 being Equals, 2 being Contains, 3 being StartsWith, and 4 being EndsWith and then after the next 2 underscores being the search criteria.
I first thought I was going down the right path by using JavaScript to modify to the desired URL via daisy-chaining all fields with the search criteria using a CONTAINS. I then noticed that decimal fields like [Cost] and DateTime (Oracle DB) fields like [Acquired_Date] have criteria settings of Equals, Greater Than, and Less Than, so I tried:
$('#SearchIcon').on("click", function (e) {
window.location = window.location.href.substr(0, window.location.href.indexOf('?'));
window.location = "?grid-filter=FIELD1__2__" + document.getElementById("Search").value +
"&grid-filter=FIELD2__2__" + document.getElementById("Search").value +
"&grid-filter=COST__1__" + document.getElementById("Search").value +
// etc. -- ALL FIELDS
"&grid-filter=NOTE__2__" + document.getElementById("Search").value;
});
This technically functions, but with the [&] is searching for a record(s) that have the corresponding search criteria in EVERY field. What I need is something similar, but with an OR [||] conditioning ---- unfortunately the grid component does not contain this form of functionality.
I then thought to pass the search criteria to a controller action and use it via a multi-WHERE clause and return only the records fitting the filter to my View:
public ActionResult SearchAssets(string searchCriteria)
{
fillPagingIntervalList();
var assetSearchResults = db.ENTITY_COLLECTION.Where(m => m.ID.ToString() == searchCriteria ||
m.Model.ToString() == searchCriteria ||
m.COST.ToString() == searchCriteria ||
// etc. -- ALL FIELDS
).FirstOrDefault();
var assetCount = db.ENTITY_COLLECTION.ToList().Count();
return View(assetSearchResults);
}
This resulted in an error with the WHERE cluase, stating to view the Inner Exception for details -- ORA-12704: character set mismatch MVC. I then reduced my multiple conditions down to just 2 fields to be searched for debugging:
var assetSearchResults = db.ENTITY_COLLECTION.Where(m => m.ID.ToString() == searchCriteria ||
m.Model.ToString() == searchCriteria).FirstOrDefault();
Resulting in:
EntityCommandExecutionException was unhandled by user code.
An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' occurred in EntityFramework.dll but was not handled in user code
Additional information: An error occurred while executing the command definition. See the inner exception for details.
Inner Exception: ORA-00932: inconsistent datatypes: expected - got NCLOB
Anyone have an idea on how to get what I want working? I also tried .Where(...con1...).Where(...con2...).Where(...etc...) with the same error resulting. I figured a wildcard search across all fields would be difficult to implement, but this is proving to be a whole bigger animal than I anticipated.
This will be very slow, but try this, which will load the entire collection into objects and let LINQ do the filtering on the client side:
public ActionResult SearchAssets(string searchCriteria)
{
fillPagingIntervalList();
var assetSearchResults = db.ENTITY_COLLECTION.ToList().Where(m => m.ID.ToString() == searchCriteria ||
m.Model.ToString() == searchCriteria ||
m.COST.ToString() == searchCriteria ||
// etc. -- ALL FIELDS
).FirstOrDefault();
var assetCount = db.ENTITY_COLLECTION.ToList().Count();
return View(assetSearchResults);
}
You could try something like this:
public ActionResult SearchAssets(string searchCriteria)
{
fillPagingIntervalList();
var assetSearchResults = db.ENTITY_COLLECTION.Where(m => m.ID.ToString() == searchCriteria)
.Union(db.ENTITY_COLLECTION.Where(m =>m.Model.ToString()==searchCriteria))
.Union(db.ENTITY_COLLECTION.Where(m =>m.COST.ToString() == searchCriteria))
// etc. -- ALL FIELDS
var assetCount = db.ENTITY_COLLECTION.ToList().Count();
return View(assetSearchResults);
}
Although, ultimately I would suggest looking into something like a predicate builder. Seems to be what you are doing anyhow.
#Html.DisplayFor(modelItem => item.Quantity)*(modelItem => item.PartsPrice)
I can display 1 or both item but unable to multiply any easy solution for above situation?
Create Price property in your modal as shown below than after use of Price property to display multiplication in your view page.
Price property declaration in modal.
public decimal Price
{
get
{
return Quantity * PartsPrice;
}
}
Display in razor view page as follow.
#Html.DisplayFor(modelItem => item.Price)
Hope it will be helpful.
You can not calculate like that. You can calculate in model, otherwise if you want to calculate the values in view, you can try the following
#{
var result = Model.Quantity * Model.PartsPrice; // Calculate the price
<span>#result</span>
}
#result will display the calculated value
if suppose the model is collection then, use foreach loop
#{
foreach (var item in Model)
{
var result = item.Quantity * item.PartsPrice; // Calculate the price
<span>#result</span>
}
}
I am using CSOM to traverse through Project Server 2013 resources on a project. I am checking if the resources are generic since I have written code logic based on that. I have a BA and PM generic resources that are part of a project that I added using the Build Team feature in Project Server. These resources show up with the Generic flag checked ON when viewing them in resource center. But programmatically the IsGenericResource flag is returning False.
Here is the code snippet (relevant code within **) :
public string ProcessGenericResources(ProjectContext pc, PublishedProject publishedproject)
{
try
{
Boolean bStaffingRequestItemUpdated = false; // this will be set to True whenever a staffing list item is update
string sResourceApproverAttr = ExceptionUtility.ReadKeyFromConfig(sResourceApproverKey);
string sRet = "";
DraftProject project;
if (publishedproject.IsCheckedOut)
project = publishedproject.Draft.IncludeCustomFields;
else
project = publishedproject.CheckOut().IncludeCustomFields;
pc.Load(project, p => p.Name, p => p.Id);
DraftProjectResourceCollection ProjectResources = project.ProjectResources;
pc.Load(ProjectResources, list => list.Include(item => item.Name, item => item.Id, item => item.IsGenericResource));
pc.ExecuteQuery();
// For each generic resource, check if an item is already in the Staffing Request list. If not create one
foreach (DraftProjectResource resource in ProjectResources)
{
List<string> listRMsNotified = new List<string>(); // this is to keep track of RMs already notified
pc.Load(resource);
pc.ExecuteQuery();
**bool bGenericResource = resource.IsGenericResource;
ExceptionUtility.LogMessage("Resource=> Name:" + resource.Name + " ID:" + resource.Id + " Is Generic Resource?: " + bGenericResource);**
I found the issue. Apparently ProjectResource is not the same as EnterpriseResource. For each ProjectResource in a Project you will need to find a match in the ProjectContext.EnterpriseResources collection. The record in EnterpriseResources collection shows the correct value in the IsGeneric attribute.
One of the search functions to our website returns far too many results for one page to handle, so I am trying to add the paging function as provided by here: https://github.com/TroyGoode/PagedList
The solution builds properly and the page will load as well, however when I try to conduct a search a "NotSupportedException" is thrown on the page's controller/Index() method:
The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.
Visual Studio 2010 points to the return statement when this exception is thrown. This is only my second day working in ASP MVC so any and all suggestion are welcome. Thank you!
case "name":
//if no comma, do a combined search by last name and by corporate name.
searchString = searchString.ToUpper();
var lastAgents =
db.Agent.OrderBy(s => s.LastName).Where(s => s.LastName.ToUpper().StartsWith(searchString)).Include(
a => a.AgentIdentification).Include(a => a.SymetraNumberToAgentId);
//end new code
var corp2Agents =
db.Agent.OrderBy(s => s.CorporateName).Where(s => s.CorporateName.ToUpper().StartsWith(searchString)).Include(
a => a.AgentIdentification);
if ((corp2Agents.Count() == 0) & (lastAgents.Count() == 0)) ViewBag.ErrorMessage = "None found in search for Last Names and Companies beginning with " + search1;
else ViewBag.Message = "Results of Last Name and Company Name search. Found " + (corp2Agents.Count() + lastAgents.Count()).ToString();
pageNumber = (page ?? 1);
return View(lastAgents.Union(corp2Agents).ToPagedList(pageNumber, pageSize));
Took forever but I found the answer. Both these statements
var lastAgents =
db.Agent.OrderBy(s => s.LastName).Where(s => s.LastName.ToUpper().StartsWith(searchString)).Include(
a => a.AgentIdentification).Include(a => a.SymetraNumberToAgentId);
//end new code
var corp2Agents =
db.Agent.OrderBy(s => s.CorporateName).Where(s => s.CorporateName.ToUpper().StartsWith(searchString)).Include(
a => a.AgentIdentification);
contain an OrderBy, however this is necessary in the Union statement as well. The final "return" statement is as follows:
return View((lastAgents.Union(corp2Agents)).OrderBy(s => s.sNumber).ToPagedList(pageNumber, pageSize));
Try adding the .OrderBy(s => s.sNumber) in the controller like this:
var lastAgents =
db.Agent.Where(s => s.LastName.ToUpper().StartsWith(searchString)).Include(
a => a.AgentIdentification).Include(a => a.SymetraNumberToAgentId).OrderBy(s => s.sNumber);
//end new code
var corp2Agents =
db.Agent.Where(s => s.CorporateName.ToUpper().StartsWith(searchString)).Include(
a => a.AgentIdentification).OrderBy(s => s.CorporateName);
All,
I've read through a lot of posts about Checkboxes and ASP.MVC but I'm not that much wiser.
My scenario:
I have a strongly typed View where I pass a collection of summary objects to the view for rendering in a for-each. This summary object contains label data based on a unique id. I also add a checkbox to the row so do so via:
<td>
<%= Html.CheckBox("markedItem", Model.MarkedItem, new { TrackedItemId = Model.Id })%>
</td>
When I perform a POST to get the submitted results my action method takes the strongly typed ViewModel back but the original summary object that I used to create the list is not populated.
Ok, this is annoying, but I can understand why so I'll live with it.
What I then do is to add a new property to my ViewModel called "MarkedItem" which is a string collection.
On postback this marked item is filled with the before and after states if the checkbox has changed but nothing to tell me which key they were for. Just to clarify, if I send this
TrackedItemId = A, Value = false
TrackedItemId = B, Value = true
TrackedItemId = C, Value = false
and set the page to this:
TrackedItemId = A, Value = true
TrackedItemId = B, Value = true
TrackedItemId = C, Value = false
I will get back this:
MarkedItem[0] = true
MarkedItem[1] = false
MarkedItem[2] = true
MarkedItem[3] = false
in other words [0] is the new value and [1] is the old value, [2] and [3] represent values that haven't changed.
My questions are:
Is this right - that I get before and after in this way? Is there any way to only send the latest values?
How can I get hold of the custom attribute (TrackedItemId) that I've added so that I can add meaning to the string array that is returned?
So far I like MVC but it not handling simple stuff like this is really confusing. I'm also a javascript noob so I really hope that isn't the answer as I'd like to return the data in my custom viewmodel.
Please make any explanations/advice simple :)
<p>
<label>
Select project members:</label>
<ul>
<% foreach (var user in this.Model.Users)
{ %>
<li>
<%= this.Html.CheckBox("Member" + user.UserId, this.Model.Project.IsUserInMembers(user.UserId)) %><label
for="Member<%= user.UserId %>" class="inline"><%= user.Name%></label></li>
<% } %></ul>
and in the controller:
// update project members
foreach (var key in collection.Keys)
{
if (key.ToString().StartsWith("Member"))
{
int userId = int.Parse(key.ToString().Replace("Member", ""));
if (collection[key.ToString()].Contains("true"))
this.ProjectRepository.AddMemberToProject(id, userId);
else
this.ProjectRepository.DeleteMemberFromProject(id, userId);
}
}
With thanks to Pino :)
ok, one hack I've come up with - I really hate that I have to do this but I don't see another way round it and I'm sure it will break at some point.
I've already implemented by own ModelBinder to get round some other issues (classes as properties for example) so have extended it to incorporate this code. We use Guid's for all our keys.
If there are any alternatives to the below then please let me know.
Html
<%= Html.CheckBox("markedItem" + Model.Id, false)%>
C#
(GuidLength is a const int = 36, Left and Right are our own string extensions)
//Correct checkbox values - pull all the values back from the context that might be from a checkbox. If we can parse a Guid then we assume
//its a checkbox value and attempt to match up the model. This assumes the model will be expecting a dictionary to receive the key and
//boolean value and deals with several sets of checkboxes in the same page
//TODO: Model Validation - I don't think validation will be fired by this. Need to reapply model validation after properties have been set?
Dictionary<string, Dictionary<Guid, bool>> checkBoxItems = new Dictionary<string, Dictionary<Guid, bool>>();
foreach (var item in bindingContext.ValueProvider.Where(k => k.Key.Length > GuidLength))
{
Regex guidRegEx = new Regex(#"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");
if (guidRegEx.IsMatch(item.Key.Right(GuidLength)))
{
Guid entityKey = new Guid(item.Key.Right(GuidLength));
string modelKey = item.Key.Left(item.Key.Length - GuidLength);
Dictionary<Guid, bool> checkedValues = null;
if (!checkBoxItems.TryGetValue(modelKey, out checkedValues))
{
checkedValues = new Dictionary<Guid, bool>();
checkBoxItems.Add(modelKey, checkedValues);
}
//The assumption is that we will always get 1 or 2 values. 1 means the contents have not changed, 2 means the contents have changed
//and, so far, the first position has always contained the latest value
checkedValues.Add(entityKey, Convert.ToBoolean(((string[])item.Value.RawValue).First()));
}
}
foreach (var item in checkBoxItems)
{
PropertyInfo info = model.GetType().GetProperty(item.Key,
BindingFlags.IgnoreCase |
BindingFlags.Public |
BindingFlags.Instance);
info.SetValue(model, item.Value, null);
}