0

I know there are a lot of similar question here but none seem quite the same as mine.

In my View:

@model LocalInformedMotionServer.Models.FeedData
@Html.DropDownList("Premise", Model.LoadUp("key"), new { @style = "width: 218px;height:35px;" })

In my controller:

public class CloudController  : Controller
{
    public IEnumerable<wsCommon.Premise> Premises { get; set; }
    public ActionResult Feed(string key)
    {
        var feedData = new FeedData();
       Premises= feedData.LoadUp(key);
        return View(feedData);
    }    
}

In my Model:

public class FeedData
{
    public IEnumerable<wsCommon.Premise> LoadUp(string saltKey)
    {
        Premises premises = new InformedBiz.Premises();
        return premises.GetPremises(saltKey);
    }
}

It errors because the variable:

   "key" 

in this call:

  Model.LoadUp("key")

is being read in as'null' in my controller method.

Of course as this is all new to me I could be doing this all wrong..

ADDITIONAL:

In my CloudController Class I have this:

 public class CloudController  : Controller
    {
    public ActionResult Feed(string saltKey)
    {
        var feedData = new FeedData();
        feedData.LoadUp(saltKey); 
        return View(feedData);
    }

    public ActionResult Index()
    {
        return View();
    }
    public ActionResult LogIn()
    {
        return View();
    }
}
Andrew Simpson
  • 6,883
  • 11
  • 79
  • 179
  • 1
    _"read in as 'null' in my controller method"_? Do you mean `null` in the models `LoadUp()` method? (`Model.LoadUp("key")` is not calling a controller method - its calling the method in your model). In any case this is bad design. Your model should not have methods that call other services. Use a view model or add the collection to a `ViewBag` property. –  Mar 01 '15 at 04:56
  • @StephenMuecke hi thanks for educating me. Point taken. I don't want to use view bag so I need to find out what and how to urs a view model. Thank you – Andrew Simpson Mar 01 '15 at 05:47
  • 1
    Wise decision :). Its a bit hard to understand what your actually trying to do here. Your controller method accepts parameter `key` which appears to filter a collection of `Premise` which you assign using `Premises = feedData.LoadUp(key);` but never then never use it. How is the collection of `Premise` related to property `Cameras`? Are you wanting to display a filtered collection of `Premise` in the dropdown (based on `key`)? –  Mar 01 '15 at 05:56
  • God I am a confusing idiot. 'Cameras' should have read 'Premises'. The flow is this: a model is passed to my view. The view will render all types of data. At the mo just focusing on 'Premises'. My dal layer - not using EF yet - returns a list of Premise objects. A Premise object has properties: name & key. I want the names displayed in drop down and key passed back to server using web api on selection of name. Is that better? – Andrew Simpson Mar 01 '15 at 06:03
  • Better, but still a bit confused. Does `FeedData` contain a property which is typeof `Premise`, and you want a dropdown to display all `Premise` objects, so you can save the selected one? –  Mar 01 '15 at 06:10
  • lol. it is my fault. I know this. I have 2 Views: 'LogIn' and 'Feed'. Both of these Views are under the Sub-Folder Cloud. So, I assume then that my Controller called 'CloudController' is responsible to passing a Model to both of my Views? In my Controller page I have:{I will edit my question for this bit} – Andrew Simpson Mar 01 '15 at 06:19
  • @StephenMuecke Question: as I am not using ViewBag am I still suing the MVC pattern? – Andrew Simpson Mar 01 '15 at 06:22
  • `ViewBag` has nothing to do with the 'MVC' pattern. It's just a way of passing additional properties (such as a `SelectList` used in `DropDownListFor()`) to your view for those too lazy to use a view model. –  Mar 01 '15 at 06:32

2 Answers2

2

I'm not sure what your Premise class looks like, but I usually use an IEnumberable of SelectListItem for drop downs in my views. So you could do something like this:

public IEnumerable<SelectListItem> LoadUp(string saltKey)
{
    Premises premises = new InformedBiz.Premises();
    return premises.GetPremises(saltKey).Select(
    p => new SelectListItem { Text = p.Name, Value = z.PremiseId.ToString() }
    );
}

You'll also need to create a Post ActionResult method that accepts the model in your view (FeedData) as well as wrap your DropDownList control in a Html.BeginForm, to post results to the controller. Hope this makes a bit of sense.

wooters
  • 829
  • 6
  • 24
  • Hi thanks for he info. Your answer does help a bit but I think I need to know how to use a view model. Point taken about the HTML.begin stuff but I will be using the web api to send data to server – Andrew Simpson Mar 01 '15 at 05:49
  • No problem. Looks like Stephen's answer above will suffice. – wooters Mar 01 '15 at 19:16
1

You have not posted the properties of your FeedData model but assuming it contains a property which is typeof Premise and you want to be able to select a Premise from a collection, then using a view model that represents what you want to display/edit is the recommended approach (refer View Model Design And Use In Razor Views and What is ViewModel in MVC?)

You view model might look like

public class FeedDataVM
{
  .....
  [Display(Name = "Premise")]
  [Required(ErrorMessage = "Please select a Premise")]
  public int? SelectedPremise { get; set; }
  ....
  public SelectList PremiseList { get; set; }
}

and in your controller (not sure what saltKey is for?)

public ActionResult Feed(string saltKey)
{
  FeedDataVM model = new FeedDataVM();
  IEnumerable<Premise> premises = // get the collection of premise objects from your repository
  // assuming you want to display the name property of premise, but post back the key property
  model.PremiseList = new SelectList(premises, "key", "name");
  return View(model);
}

View

@model FeedDataVM
@using(Html.BeginForm())
{
  ....
  @Html.LabelFor(m => m.SelectedPremise)
  @Html.DropDownListFor(m => m.SelectedPremise, Model.PremiseList, "-Please select")
  @Html.ValidationMessageFor(m => m.SelectedPremise)
  ....
  <input type="submit" value="Save" />
}

and the POST method

public ActionResult Feed(FeedDataVM model)
{
  // model.SelectedPremise contains the value of the selected option as defined by the key property of Premise
}

Side note: Your FeedData model contains a method to retrieve a collection of Premise which appears to be calling another service. You should avoid this type of design which makes it difficult to debug and unit test. Your controller is responsible for initializing/getting you data models and view models and for populating/mapping their properties.

Community
  • 1
  • 1
  • Hi, thanks for this. I was just looking all this up with comments you have made so far. So: to conclude then. The Model will contains my lists, collections, properties etc and they will in turn call methods to get that data. These calls are made outside of Model and Controller? This is the best practice? This looks 'clean' and better to Unit Test but I have been known to go off on a tangent before! – Andrew Simpson Mar 01 '15 at 07:06
  • The @SaltKey is like an 'Id' that is passed to my Stored Procedure. – Andrew Simpson Mar 01 '15 at 07:10
  • No. A view model (and in general your data models) should only contain properties that represent you data. Any methods that get and save your data models should be in a separate service, for example `PremiseRepository.Fetch()` might return a collection of all `Premise` objects or `FeedRepository.Get(int ID)` might return a single `FeedData` object. Your controller is responsible for calling these methods, initializing the view model, and passing that view model to the view –  Mar 01 '15 at 07:16
  • Hi, is that not what I implied? You stated : IEnumerable premises = // ~ in the Controller which will have to call a method from another class/method?. – Andrew Simpson Mar 01 '15 at 07:19
  • 1
    Perhaps I misunderstood your comment _"model will contains ... properties etc and they will in turn call methods"_ which I interpreted as _the model calls the method_ which it shouldn't - its the controller which calls the methods in your service (not a method in your model) to populate the model. –  Mar 01 '15 at 07:24
  • BTW, you do not have to keep replying to my questions. I know I am demanding. It is just the way I learn {autistic you see} It can seem I ask simple questions and the same questions in a slightly different way. I am just determined to do things right :) – Andrew Simpson Mar 01 '15 at 07:24
  • You just posted. Actually, you were correct I did comment it wrongly. Yes, the method calls are in the controllers, the Model contains the object definitions and actually getting the data will go to the tradition DAL and BIZ layers whether services, MSMQ or Entity Framework etc - . I think I got it now. Now to tackle RouteConfig :) – Andrew Simpson Mar 01 '15 at 07:28