2

Very new to ASP.Net, moving from PHP. So I'm pretty sure I've broken every rule in the book here but anyway here is what I am trying to accomplish.

I have a page that allows our parkade (car park) operators to update the counts of cars in a parkade at any given time.

What I want to achieve is to have a page that lists the parkades and their respective available parking spots and used parking spots. I am using jQuery to make it so that when say for example the free spaces text box is updated the used spaces adjusts itself accordingly. So for example in a parkade with 100 total parking spots, when someone types 10 into the free spaces box the used spaces box will automatically update itself to 90.

Form example:

form format

So I had to do some wizardry (which I suspect was wrong) to make this work (i.e. add a dynamic ID to each text field so that I knew which text boxes to update during the onblur event.

Anyway this all works great but alas my validation does not work. I suspect this is due to my dynamic generation of forms.

Here is my view code:

  model IEnumerable<WebApplication1.Models.ParkingCount>

@{
    ViewBag.Title = "Parking Lot Administration";
}

<h2>Parking Lots</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>

<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.parkingLotName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.parkingSpaces)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.freeSpaces)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.usedSpaces)
        </th>
        <th></th>
    </tr>
@{int i = 0;}
@foreach (var item in Model)
{
    using (Html.BeginForm("UpdateParkingLot", "ParkingCount", FormMethod.Post, new { @Id = "Form" + i}))

    {
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <tr>
        <td>
            @Html.HiddenFor(modelItem => item.ID)
            @Html.DisplayFor(modelItem => item.parkingLotName)

        </td>
        <td>          
            @Html.TextBoxFor(modelItem => item.parkingSpaces, new { id = "parkingSpaces" + i })
            @Html.ValidationMessageFor(modelItem => item.parkingSpaces, "", new { @class = "text-danger" })
        </td>
        <td>
            @Html.TextBoxFor(modelItem => item.freeSpaces, new { id = "freeSpaces" + i })
            @Html.ValidationMessageFor(modelItem => item.freeSpaces, "", new { @class = "text-danger" })
        </td>
        <td>
            @Html.TextBoxFor(modelItem => item.usedSpaces, new { id = "usedSpaces" + i })
            @Html.ValidationMessageFor(modelItem => item.usedSpaces, "", new { @class = "text-danger" })
        </td>
        <td>
            <button type="submit">Update</button>
        </td>
    </tr>

    }
    i++;


}

</table>

@for (int j = 0; j <= i; j++)
{


<script>

    $("#parkingSpaces0").blur(function () {


        var i = @i;

        var totalSpacesValue = $(this).val();
        var usedSpacesValue = $("#usedSpaces0").val();


        $("#freeSpaces0").val(totalSpacesValue - usedSpacesValue);

    }
    )

    $("#freeSpaces0").blur(function () {

    var totalSpacesValue = $("#parkingSpaces0").val();
    var freeSpacesValue = $("#freeSpaces0").val();

        $("#usedSpaces0").val(totalSpacesValue - freeSpacesValue);


})

    $("#usedSpaces0").blur(function () {

    var totalSpacesValue = $("#parkingSpaces0").val();
    var usedSpacesValue = $("#usedSpaces0").val();

        $("#freeSpaces0").val(totalSpacesValue - usedSpacesValue);


    })

</script>
}

Here is my model code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace WebApplication1.Models
{
    public class ParkingCount { 

        public int ID { get; set; }

        [Display(Name="Parking Lot Name")]
        public string parkingLotName { get; set; }

        [Required]
        [Display(Name ="Total Parking Spaces")]
        public int parkingSpaces { get; set; }

        [Required]
        [Display(Name ="Free Parking Spaces")]
        public int freeSpaces { get; set; }

        [Required]
        [Display(Name = "Used Parking Spaces")]
        public int usedSpaces { get; set; }

    }
}

And finally my (incomplete) controller code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using CsvHelper;
using System.IO;


namespace WebApplication1.Controllers
{

    public class ParkingCountController : Controller
    {
        // GET: ParkingCount
        public ActionResult Index()
        {

            //create an instance of our service class
            WebApplication1.ServiceClasses.GetParkadeDetails myCounts = new WebApplication1.ServiceClasses.GetParkadeDetails();

            //create list objec to store parkade objects
            List<WebApplication1.Models.ParkingCount> myList = new List<WebApplication1.Models.ParkingCount>();

            //read in the CSV files of parking lots (c:\parkingLots.csv)
            StreamReader sr = new StreamReader("c:\\parkingLots.csv");
            CsvReader csvRead = new CsvReader(sr);
            IEnumerable<WebApplication1.ServiceClasses.ParkingLotRecord> lines = csvRead.GetRecords<WebApplication1.ServiceClasses.ParkingLotRecord>();

            //add the parking lots to our list
            foreach (var line in lines)

                myList.Add(new Models.ParkingCount
                {
                    ID = line.parkingLotID,
                    parkingLotName = line.parkingLotName,
                    freeSpaces = myCounts.getFreeStalls(line.parkingLotID),
                    parkingSpaces = myCounts.getStallCount(line.parkingLotID),
                    usedSpaces = myCounts.getUsedStalls(line.parkingLotID)

                });

            return View(myList);
        }

        public ActionResult UpdateParkingLot(Models.ParkingCount item)
        {

            try
            {
                //Update the parking counters here
                int parkingLotID = item.ID;
                int freeSpaces = item.freeSpaces;

                System.Diagnostics.Debug.WriteLine(freeSpaces + " free spaces at Parking Lot " + parkingLotID);

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }


        }


    }
}

Any idea how I could get my validation working?

Thanks for any help in advance.

John.

John McAulay
  • 185
  • 9
  • Did you try adding "required" and adding data-rules to your form fields? – Mark S Apr 27 '16 at 20:45
  • show us your `Model` and `Controller` – jamiedanq Apr 27 '16 at 20:49
  • Not only will validation not work, binding will fail as well. You creating form controls that have no relationship to your model (look at the html your generating - you have inputs with `name="item.parkingSpaces" and your model does not have a property name `item`). What are you trying to achieve with this - you can only submit one form at a time so your view makes no sense. –  Apr 27 '16 at 21:46
  • I've left work for the day, I'll post them tomorrow. – John McAulay Apr 27 '16 at 21:52
  • I've now included my controller and model code. The bindings do seem to work in that I can access the field values in my controller. I am trying to achieve a page with all parking lots listed in one place, where our operators can update the parking lot counts, without having to click on an edit button. They will be using an iPad / Android tablet to update these counts so the less clicks for them the better. Hence the need for all parking lots on one page. – John McAulay Apr 28 '16 at 14:41
  • The parking lots do automated counting (i.e. magnetic loops count when a vehicle enters / exits a parking lot. However these counts need to be verified and occassionally change) We will be bringing more parking lots onto this system very soon, hence the need for a dynamic number of forms on the page (the parking lots are read in from a CSV file). Does that make sense? – John McAulay Apr 28 '16 at 14:42
  • Sorry, but none of your code makes any sense. Nothing you have shown will work. No validation, no binding when you submit and even you scripts cannot work correctly. Other than giving you an answer which points out why it wont work - which I suspect you don't really want - its a bit hard to to show you how to do this correctly unless you update the question with more detail explaining what your trying to achieve. –  Apr 29 '16 at 03:33
  • Do for example you want to be able to edit all `ParkingCount` objects in the collection and be able to post them all in one action (which would seem the most appropriate solution), or do you really want to edit only one `ParkingCount` at a time? –  Apr 29 '16 at 03:51
  • Hi Stephen, Sorry for the confusion, ideally I would like to be able to edit one ParkingCount at a time. But have them all on the one page. Let me know if I can provide any more information. – John McAulay Apr 30 '16 at 01:59
  • @JohnMcAulay, To notify a user, start the comment as this one does. You code really wont do that, and your scripts wont make sense. It not really clear why you want to edit and submit only one at a time, but if you do, then the view should include text only values and a since form for editing the selected row - refer [this DotNetFiddle](https://dotnetfiddle.net/Yy78S3) for an example of how to approach that –  May 01 '16 at 00:06
  • But it would make more sense (and certainly improve performance) if you have one form and the controls generated in a `for` loop or `EditorTemplate` and you submit all changes at once (refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) for an example. Although in both cases your scripts need to be corrected. –  May 01 '16 at 00:08
  • @StephenMuecke thanks for this, really appreciate it. Ideally I do want to be able to edit inline with all parking los shown on one page, if at all possible. The app will only be used on a tablet so I was hoping to minimize the amount of clicks a user has to make. Is what I'm trying to do even possible? I am a PHP developer and I could do it pretty easily with PHP, so I assume it must be possible in .NET. – John McAulay May 02 '16 at 14:43
  • @JohnMcAulay, Sure - just use one form and a `for` loop or `EditorTemplate` to generate the controls and post back the collection in one go. Refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) to get you started –  May 02 '16 at 23:06
  • @StephenMueckle Hi sorry, I'm back on this project now. I think I'm just going to code the thing in PHP, I've spent way too long on this, what I thought would be a good starting project in ASP.Net / MVC has turned into a complete nightmare for me. Why I can't have multiple forms on the same page (with each form relating to one element within my model) is beyond me. Thanks for your help. Can you recommend any good reading / websites that might be able to help me if I do ever try ASP.Net again? – John McAulay Jun 09 '16 at 17:24

0 Answers0