MediaLibraryPickerField Recommended Usage and EditorFor in Razor

Topics: General
Nov 16, 2013 at 12:18 AM
Edited Nov 16, 2013 at 12:21 AM
Hi,

I've created a part (PersonPart) with MediaLibraryPickerFIeld so that an image can be attached for a person.

The PersonPartRecord/PersonPart classes have simple string Name/Email properties and MediaLibraryPickerField is added through migrations.

Everything works through the Dashboard. Fields are rendered properly and since MLPField is attached in migration, an editor is automatically rendered in the shape for it.

Now, I want to create the above (working) Person through the regular MVC way.
 public class CreatePersonViewModel
    {
        [Required(ErrorMessage = "Name is required")]
        public string Name { get; set; }

        [Required(ErrorMessage="Email is required")]
        public string Email { get; set; }

        public MediaLibraryPickerField Picture { get; set; }
    }
I create a Shape in Public ActionResult Create() and have the below template for the View:
@using AA.Person.ViewModels

@{
    var person = (CreatePersonViewModel)Model.Create;
}

<div class="person_create">

    @using (Html.BeginFormAntiForgeryPost(Url.Action("Create", "Person", new { area = "AA.Person" })))
    {
        <fieldset>
           
            @* Editors for name email left out*@

            <div class="editor-label">
                @Html.LabelFor(m => person.Picture)
            </div>
            <div class="editor-field">
                @Html.EditorFor(m => person.Picture)
                @Html.ValidationMessageFor(m => person.Picture)
            </div>
            <p>
                <input type="submit" value="Create Person" />
            </p>
        </fieldset>
    }
</div>
As someone familiar with the above might already know, It does not work.

So my questions are below:
  1. Can a MediaLibraryPickerFIeld be used through razor template and if so, how?
  2. What is the recommended approach for lets say adding a picture to the PersonPart. (which I know relates to 1).
Any advice is appreciated. thanks.
Coordinator
Nov 16, 2013 at 5:44 AM
I don't understand why you have a property of type MediaLibraryPickerField. That doesn't make sense if you added the field through the migration.
Nov 16, 2013 at 2:42 PM
Edited Nov 16, 2013 at 5:37 PM
That MLPF came from the ViewModel that I defined to create a person.

Here are a couple of things I tried:
  1. Using ViewModel to create a person: (The ViewModel is described in the code snippet at the top with MLPF included)
    a. Create() action in controller did this:
[Themed]
        public ActionResult Create()
        {
            var shape = _services.New.Person_Create(Model: new CreatePersonViewModel());
            return new ShapeResult(this, shape);
        }        
and Person.Create.cshtml did this:
@using Arjun.Person.ViewModels
@{
    var model = (CreatePersonViewModel)Model;

   var pictureField = (MediaLibraryPickerField)(from field in Model.Fields
                                                 where field.Name == "Picture"
                                                 select field).FirstOrDefault();

}

<div class="editor-label">
                @Html.LabelFor(m => pictureField)
            </div>
            <div class="editor-field">
                @Html.EditorFor(m => pictureField)
                @Html.ValidationMessageFor(m => pictureField)
            </div>
...
The above didn't work. (again what I was doing was having a viewmodel with MLPF included and fed it as a new() item in shape to the view)
b. Tried using PersonPart itself as a new() item to the shape being created:
 [Themed]
        public ActionResult Create()
        {
            var shape = _services.New.Person_Create(Model: new PersonPart());
            return new ShapeResult(this, shape);
        }

and my Person.Create.cshtml view

@using Orchard.MediaLibrary.Fields
@model Arjun.Person.Models.PersonPart

@{
    var dynamicModel = (dynamic)Model;
    var pictureField = dynamicModel.Fields.Picture;
}


 <div class="editor-label">
                @Html.LabelFor(m => pictureField)
            </div>
            <div class="editor-field">
                @Html.EditorFor(m => pictureField)
                @Html.ValidationMessageFor(m => pictureField)
            </div>
Here again, what I tried to do was feed a new PersonPart() to the shape being crated in controller. Convert that shape to dynamicModel in view so that I can get to the Picture field, and render an EditorFor(m => pictureField)

So Both options a, b are not working.

What is the best way to do this?
a. With a ViewModel that has MLPF included so that razor can do : EditFor(m => @Model.Picture) b. Feed a new instance of PersonPart in controller, and get to that field in razor view to render UI for MLPF
c. Information that will be most helpful for me is: All tutorials or examples show how to Display a MLPF. But where i'm running into problems is, if the MLPF is added in Migrations, and I want a Razor view to show an option to the user to upload the media (not in the admin view, but in a front end page like an <input type="file"> type of scenario).

Again, I might be going entirely in the wrong way of it, but wanna figure this out.

Thanks.
Coordinator
Nov 17, 2013 at 5:31 AM
Edited Nov 17, 2013 at 5:33 AM
Why do you have a view model if you're going to use a shape? Why do you even need to get to the media library picker field? Why don't you just place that field, using placement?
Nov 17, 2013 at 2:14 PM
Edited Nov 17, 2013 at 2:20 PM
Here's what I tried to do after I saw your suggestion.

a. I saw that the Display() driver method for MediaLibraryPickerField (MLPF) creates a shape : Fields_MediaLibraryPicker
I placed it in Placement.Info as: <Place Fields_MediaLibraryPicker="Content:0"/>

b. Here are my Create() and CreatePOST methods in controller:
[Themed]
        public ActionResult Create()
        {
            var shape = _services.New.Person_Create();
            return new ShapeResult(this, shape);
        }

       
        [Themed, HttpPost]
        public ActionResult Create(PersonPart person)
        {
            throw new NotImplementedException();
        }
c. My view (Views/Person.Create.cshtml) has this code to create an editor for the Create() action method
@model Arjun.Person.Models.PersonPart

<div class="person_create">

    @using (Html.BeginFormAntiForgeryPost(Url.Action("Create", "Person", new { area = "Arjun.Person" })))
    {
        <fieldset>
            <p>Create a new person</p>
            <div class="editor-label">
                @Html.LabelFor(model => model.Name)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>

            <div class="editor-label">
                @Html.LabelFor(model => model.Email)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Email)
                @Html.ValidationMessageFor(model => model.Email)
            </div>

            @* MLPF is added in migrations and should show up here if the Placement.info contains it? *@

            <p>
                <input type="submit" value="Create Person" />
            </p>
        </fieldset>
    }
</div>
As you can see from the @**@ comment in code, MLPF should show up there.

Things I might not be doing right:
  1. In the Create() method, while creating the Person_Create shape, would I need to feed a new instance of PersonPart() like we do in MVC?
    as in: Person_Create(Model: new PersonPart())
  2. Would it be okay to just have Create() the way it is and have a @model Arjun.Person.Models.PersonPart as the @model for the view?
  3. Am I not correct in creating Place<> for Fields_MediaLibraryPicker? should I target a specific ContentType such as:
    <Match ContentType="Person">
    <Place Fields_MediaLibraryPicker="Content:0"/>
    </Match>
I have tried the options above and they are not working.

Tell me what needs to be corrected.

Thanks for your suggestions till now, and more to come.
Nov 17, 2013 at 7:34 PM
Edited Nov 17, 2013 at 7:39 PM
Bertrand,

I see that you've told MLPF cant be used on front end, or Image Field for that matter. (http://stackoverflow.com/questions/18743405/orchard-1-7-add-image-upload-field-to-custom-form).
(http://stackoverflow.com/questions/19317798/how-to-add-image-file-uploader-in-custom-form-orchard-cms).

Also Sebastien Ros said something similar about MLPF (https://orchard.codeplex.com/workitem/20174)

I guess that is what I was trying to do. Attach an image for the person in the front end.

Is custom way the only option of proceeding? by that I mean:

a. Create a file upload <input type="file"> on the front end, handle posted file in the controller, and insert into ConentType by newing up an instance in lets say IPersonService:
Something like: var person = _contentManager.New("Person") and inserting other fields?

Let me know if you can.

Thanks.
Coordinator
Nov 18, 2013 at 12:44 AM
Yes, if you want to allow front-end users to upload images, you'll have to use a file upload form, and handle that from a custom controller. You'll also have to handle the secure storage of those files.
Marked as answer by robroysd on 11/17/2013 at 4:53 PM
Nov 18, 2013 at 12:53 AM
Alright, thanks for the advice.

Will figure out a way to handle front-end postback and also look into secure storage.