Archive for category jQuery

Creating an Order/ Order Details style view using ASP.net MVC2 & Entity Framework 4

Before you start reading, beware!  I’m posting this because I’ve got a working solution, but I’m not convinced it’s the correct way to do this- I’m an MVC beginner myself so I’m hoping someone will post to either day “looks good” or say “this is ridiculous!” so don’t follow what i’ve written here as if it’s a tutorial!

I’ve just started my very first MVC2 project- it’s a pretty simple web based back office Warehouse/Order management system, tying into a frontend website. I boshed out a whole bunch of simple list/edit screens for Parts/ Couriers/ Stock movements etc saving the Order entry form till last as I couldn;t immidiatly imagine how this would work. What I wanted was the equivilant of an old school Access form with a sub form- like so;

edit_form

(Obviously, once everything’s working I will substitute the crazy GUID fields for some kind of swanky jQuery lookup!)

I started MVC following through Scott Hanselmans’ tutorials over on the Microsoft MVC site which shows building up a database, using Entity Framework 4 as an ORM, and extending those Model classes to set validation meta data- then building your simple controllers and a bunch of strongly typed views against these Entity Framework model classes (and some view models as required).

This all works fine when building one set of views per table- so I have a Parts database table, which I create a Parts controller for, then have a simple List, Create and Edit view which all works very well- the UpdateModel method happily updated my Model class from the form data on the strongly typed views.  It all becomes a little less clear though when you have a record which has a bunch of other associated records.  I need to not only Bind to a single records field, but also Bind to a List<> of associated records.

So I started googling and I found a bunch of links on google about binding to lists in MVC, including 3 quite pivotal ones all linked off of this StackOverFlow article;

There’s also an additional article off the back of one of those articles;

These links are all great and give good working examples of Binding to an object with a property which is a List<> of another object– but none of these are tied to any kind of data persistance which seems contrary to most of the MVC tutorials which show how easily you can write your controllers and view straight against the EF objects.  I can understand that in a full blown enterprise system you’re not going to be tying yourself straight to the EF classes anyway and you’de probably have a ViewModel or some kind of DTO which you pass between your data layer and your controllers- but I wanted to see this done with the EF objects, as I don’t think its something which should be difficult.

So I tried following the various methods but using my Entity Framework objects and had a whole world of problems.  Using Donn felker’s method I recieved this error;

“Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.”

I think I did eventually get past this error, but then I was hit by the same erorr I got using Steve Sanderson’s original method which was

“UpdateModel The EntityCollection has already been initialized. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph”

This caused a Model error and stopped the form going through – I read various forum posts about removing this error from the ModelState error stack, but the save still failed.  I also experienced a bunch of other problems with the html field’s not being given the correct ID’s to map back to the models when using the HtmlPrefixScopeExtensions class that was part of the solution in the above articles. So I tried a whole bunch of variations of various articles I’d read and eventually gave up and decided to do something a bit different.

My Approach

In the model I have the entity model of my database, which gives me the Sale and SaleLine class- I create partial classes for these which hold the validation metadata.  I then created a ViewModel which will hold a single Sale and a List<SaleLine>, which are the lines which correspond to that sale.

If I bound the view straight to the Sale, then I would get SaleLines for free as a navigation item on the Sale class- i could dump the properties of the Sale to the form like normal, then just do a for loop going round Model.Salelines- when I post back then I have a single Sale object, with its attached records which can be automatically updated. But this seemed to be one of the issues I was having- when posting back, MVC was trying to rebuild my Sale object from the view data, which it did with no problems, but when it came to reattaching all the associated SaleLines, entity framework would start complaining that they already exist. So splitting them out in the ViewModel breaks the SaleLines out of the EntityCollection and just creates a generic List of SaleLines which I can itterate through using an index and then process manually on the post back.

// Model Partial Classes

[MetadataType(typeof(SaleMetadata))]
public partial class Sale
{
public Sale() {
this.Id = Guid.NewGuid();
this.CreateDate = DateTime.Now;
}
class SaleMetadata
{
// TODO
}
}

[MetadataType(typeof(SaleLineMetadata))]
public partial class SaleLine
{
class SaleLineMetadata {
[Required(ErrorMessage = "Please enter a quantity.")]
[Range(1,99999,ErrorMessage="Quantity must be at least 1!")]
public object Qty { get; set; }
}
}

// ViewModel

public class SaleViewModel
{
public Sale Sale { get; set; }
public List<SaleLine> SaleLines { get; set; }
}

On my SaleController’s Edit method, I setup the ViewModel and return it to the View.

public ActionResult Edit(Guid id)
{
SaleViewModel svm = new SaleViewModel()
{
Sale = db.Sales.Single(x => x.Id == id),
SaleLines = db.SaleLines.Where(x => x.SaleId == id).ToList()
};

return View(svm);
}

The View is a standard Edit view, with the for loop at the bottom to render out the Salelines;

<fieldset><legend>Items</legend>

<table id="rows">
<tr>
<th>Part Id</th>
<th>Qty</th>
<th>Sale Price</th>
<th>&nbsp;</th>
</tr>

<% for (int i = 0; i < Model.SaleLines.Count; i++ )
{ %>
<tr>
<td>
<%: Html.HiddenFor(model => model.SaleLines[i].Id) %>
<%: Html.TextBoxFor(model => model.SaleLines[i].PartId)%>
<%: Html.ValidationMessageFor(model => model.SaleLines[i].PartId)%>
</td>

<td>
<%: Html.TextBoxFor(model => model.SaleLines[i].Qty)%>
<%: Html.ValidationMessageFor(model => model.SaleLines[i].Qty)%>
</td>

<td>
<%: Html.TextBoxFor(model => model.SaleLines[i].SalePrice)%>
<%: Html.ValidationMessageFor(model => model.SaleLines[i].SalePrice)%>
</td>

<td>
<%= Html.ActionLink("Remove", "DeleteRow", new { id = Model.SaleLines[i].Id }, new { Class = "removeItem" })%>
</td>

</tr>
<% } %>

</table>

<a href="#" id="addItem">Add another...</a>

To Handle the post back I can update the Sale as normal, then I grab a list of the SaleLines from the database, and itterate through them manually updating each one;

[HttpPost]
public ActionResult Edit(Guid id, SaleViewModel svm)
{
if (ModelState.IsValid)
{
Sale s = db.Sales.Single(x => x.Id == id);
UpdateModel(s, "Sale");

List<SaleLine> db_lines = s.SaleLines.ToList();

for (int i = 0; i < svm.SaleLines.Count; i++)
{
SaleLine form_line = svm.SaleLines[i];
SaleLine db_line = db_lines.FirstOrDefault(x => x.Id == form_line.Id);

if (db_line == null)
{
//create a new one
form_line.Id = Guid.NewGuid();
form_line.SaleId = id;
db.AddToSaleLines(form_line);
//db.SaveChanges();
}
else
{
UpdateModel(db_line, "SaleLines[" + i + "]");
}
}

db.SaveChanges();

return RedirectToAction("Index");
}
else
{
return View(svm);
}
}

Adding an extra row, is all done entirly with jQuery– and this is one of the bits that doesn’t feel right.. I grabbed the html from an existing row, then modify it myself adjusting the ID’s so it’s a new row. When the View gets posted back, MVC is clever enough to be able to pick up my new row along with the others, and I have some logic to check if this row has a corresponding row in the SaleLines list, and if not, to create a new one.

var current_count = <%=Model.SaleLines.Count %>;

$("#addItem").click(function () {
$("#rows").append('<tr><td><input type="text" value="" name="SaleLines[' + current_count + '].PartId"></td><td><input type="text" value="" name="SaleLines[' + current_count + '].Qty" ></td><td><input type="text" value="" name="SaleLines[' + current_count + '].SalePrice"></td></tr>');
current_count++;
return false;
});

$("a.removeItem").live("click", function () {
remove_row = $(this).parent().parent()
$.ajax({
url: this.href,
cache: false,
success: function(html) { $(remove_row).remove(); reNumber(); }
});
return false;
});

function reNumber() {
var i = -1;
$("#rows tr").each(function (element_id, element) {
$("input[id$='Id']", $(element)).attr('id', 'SaleLines_' + i + '__Id').attr('name', 'SaleLines[' + i + '].Id');
$("input[id$='PartId']", $(element)).attr('id', 'SaleLines_' + i + '__PartId').attr('name', 'SaleLines[' + i + '].PartId');
$("input[id$='Qty']", $(element)).attr('id', 'SaleLines_' + i + '__Qty').attr('name', 'SaleLines[' + i + '].Qty');
$("input[id$='SalePrice']", $(element)).attr('id', 'SaleLines_' + i + '__SalePrice').attr('name', 'SaleLines[' + i + '].SalePrice');

i++;
});
}

The above javascript also has a bit of code to remove rows- this calls a method on the controller (DeleteRow- see below) and then removes the table row from the html.

// AJAX GET : /Sales/DeleteRow/{RowId}
public bool DeleteRow(Guid id)
{
try
{
SaleLine line = db.SaleLines.Single(x => x.Id == id);
db.SaleLines.DeleteObject(line);
db.SaveChanges();
return true;
}
catch (Exception)
{
return false;
}
}

This broke the update method though as the indexes were no longer sequencial- the html which gets spat out by MVC puts an index number against each row, and putting gap in this numbering stops the full collectino of items being passed, so I have to renumber the remaining items (the reNumber function shown in the javascript listing above). This feel’s like a total hack; I’ve read some articles about non-sequencial indexing, but I don’t have enough MVC XP’s to be able to apply this and the interweb is a bit thin on the ground for code examples which include the all important UpdateModel and persistance part of the code!

Anyway- comments would be appreciated! Is this a completly mental way of doing things? Have you read any other articles which implement differently?

12 Comments

Grabbing mashed .net Control ID’s using jQuery

I need to grab a bunch of controls from repeater items in .net – They are all prefixed with something like ctl00_Content_ctl00_rptLines_… and then the actual ID I set for the control- with dot net v4 you can set your own client Id’s so this isn’t a problem, but i’m using an older version. It’s easy enough to do partial matches with jQuery;

$("span[id$='_txtName']") // match the section at the end

// you can also match text at the start, or in anywhere in the string using the following
$("span[id^=text]")
$("span[id*=text]")

No Comments

ASP.net Jquery to fire on partial post back

use this;

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(){
      // ... your code here!
 });

No Comments

MSDeploy Setup Guide & How to Call Server Side Method Using jQuery/Ajax

Couple of interesting items popped up in the RRS feed’s this morning.

Automating Deployment with Microsoft Web Deploy – ScottGu’s Blog.

Calling Server Side Method Using jQuery/Ajax – Karan’s Blog.

No Comments

ASP.net update panel’s and jQuery

I had a problem today with buttons in an update panel and jQuery- there are some buttons which get hidden or displayed depending on the user’s OS – mac or pc users basically get shown different instructions- However because these buttons are added by a partial post back of the update panel, the jQuery document.ready had already fired before these buttons existed.

So I experimented adding the code to the form.submit event but in the end found the solution on google; I simply added this;

<script type='text/javascript'>
function pageLoad(sender, args)
{
    // your code here..
    showHideMacLinks();
}
</script>

This handles the pageLoad event raised by my update panel which is fired on the initial load and on the partial post back.  You can filter this to only fire on partial post back by adding  “if(args.get_isPartialLoad())”

Found this over on the .net Funda blog

No Comments

HTML5 Audio and Video (Media) Tags – How do you know when the data’s loaded? And how to play multiple instances of the same sample at the same time

Quick post with a snippet of code I’ve used for the 8 week game competition I’m in- I’m going to be using html5 audio element for all my game’s sounds and needed a way to make sure the samples were totally loaded so the resource manager knows when to hand control to the game- So after flicking through the html5 spec came up with this code (utilising jQuery to bind my event handler)

Note- This applies to any media object- so the video tag as well, but I’ve only tried this with audio.

// http://www.whatwg.org/specs/web-apps/current-work/#mediaevents
// http://api.jquery.com/bind/
var ao = new Audio();
$(ao).bind('canplaythrough', function() { // totally loaded
alert('ready to play');
});
ao.src = 'sounds/my_sound.wav';
ao.load();

The above example will wait until the media element has enough data to comfortably play through without stopping to buffer. if you wanted you could also bind to a whole host of other events in exactly the same way, which you can read about here. You can check the status at any time to see how loaded the audio/video file is like this;

ao.readyState;

This will return you back a number between 0 (HAVE_NOTHING) to 4 (HAVE_ENOUGH_DATA) – full info can be found here.

Because I’m building a game I have slightly different requirements to the average web project- The way I use this is have a central “ResourceLoader” which I load up with all the url’s to the asset’s I’ll be using, this then reports when all the assets are totally loaded and hands control to the game. So there is a single instance of every image and audio element I’m using- I then hand each loaded sound to the sound manager to play. This raises a problem when i want to play the same sample more than once, overlapping because you are essentially just passing around reference to the same audio object- so i execute the play method, then execute it again and nothing happens because it is already playing! The answer is to perform a deep copy of the audio element before playing- because this is a DOM object you can do this easily like so;

// https://developer.mozilla.org/en/CloneNode
var instance1 = ao.cloneNode(true);
var instance2 = ao.cloneNode(true);
instance1.play();
instance2.play();

This way you can hit the play() method of instance1, and the instance2 and they will both play at the same time, totally independant of each other, even though they both originate from the pre-loaded instance ao.

Anyway- you can see live demos of this here;

Notice the need for 2 demos because chrome cant read wav and mozilla wont do MP3! Ogg vorbis is a common format for the two, but i couldn’t quickly find any example files to use! Read here for browser file format support.

These demo’s were made for us in the 8weekgame site – bare in mind the sound manager class I literally started about an hour ago so it’s got hardly any functionality but it does play sounds so take a look at the source code and hopefully it will all make sense!

No Comments

New site launch- natashahampshire.co.uk

Juts launched a new portfolio site for my girlfriend, www.natashahampshire.co.uk – This is just the first phase with a few more features and a bunch of extra contact to be added in the coming weeks, but we needed to get it up ASAP so she can apply for a design course in London!

No Comments

Javascript & CSS Minification

Is that a real word?

Well anyway, I’m just finishing off a fairly jQuery heavy site I’m building for my girlfriend as an online portfolio site and figured I’d minify the css and jQuery to reduce loading times (as all of my javascript includes combined come to around 100k)- found a really good java app writen by Yahoo(!) called the YUI Compressor – I combined all my javascript into one combined.js file then minified it nocking 30k off the file size.  Did the same with css only making a saving of 2-3 k, but every little helps!  Very easy to use, but it means you do have to install the java runtime :(

2 Comments

JQuery Accordion Control links not working

I recently swapped the .net Accordion control on my main home page from the Ajax Control toolkit for the jQuery Accordion control from jquery.com- this was mainly because i have a big moving flash background of the sky wooshing past, and found the MS accordion control a bit too heavy to expand out smoothly on slower machine, so thought i would try the jQuery version and was pleased to find it was a lot smoother.

However, to my horror, all my links stopped working!

$(function() {
            $("#menu").accordion({
                active: false,
                alwaysOpen: false,
                animated: "easeslide"
            });
        });
<ul id="menu" style="width: 250px;">
  <li>
    <a href="#">Welcome</a>
    <div>This is the home page to what will eventually be a whole bunch of different web projects that i have online to fiddle about with.</div>
  </li>
  <li>
    <a href="#">Work</a>
    <div>
      <ul>
        <li>
          <a title="My Web Development Blog" href="http://www.shawson.co.uk/codeblog/">My Code Blog</a>
        </li>
      </ul>
    </div>
  </li>
  <li>...</li>
</ul>

This is because the jQuery accordion, using the default settings as i was, treats links as buttons for expanding the sections of the accodion, so voids their default action.  I resolved this by updating the jQuery settings to only treat links with a specific class as the accordion headings, and leave other links alone- i created a new class called accordion-label to use for the accordion buttons and updated the jquery as follows;

$(function() {
            $("#menu").accordion({
                active: false,
                alwaysOpen: false,
                animated: "easeslide",
                navigation: true,
                header: "a.accordion-label"
            });
        });

I then added the accordion-label class to my “Welcome” link, “Work” link etc, and left the rest as-is.

No Comments

JQueryUI

As most of my colleagues will know, I love JQuery and one of our contractors, Lee, today showed me the brilliant JQueryUI library which features a whole bunch of functionality similar to the horribly bloated .net control extenders. Well worth a look over at http://jqueryui.com/

No Comments