Refresh content with filter

Topics: Writing modules
Nov 29, 2012 at 3:20 PM

How can I refresh the entire page with an Action?

I've got a form in FirstAside with a textbox and a submit button which point to an action "Search" in a controller. (All this in a widget)

What i want to do is Refresh whole page so another widget (located in Content Zone) will display informations that match the current search.

Note: I do not use content items from Orchard but external data fetched by a WebService... That's why I don't use projections.

Until now, my controller looks like this:

        public ActionResult SearchInstallation(string textToSearch) {
            //Get All the Installations
            List<Services.Customer.TransportModel.Installation.Installation> lst =
                (List<Services.Customer.TransportModel.Installation.Installation>)(new Client().GetInstallationCollection(null, null));

            List<Services.Customer.TransportModel.Installation.Installation> result;
            // Get Installations that matches textToSearch
            result = lst.FindAll(f => f.Number.Contains(textToSearch));

            //return ContentShape("Parts_Installation", () => shapeHelper.Parts_Installation(ContentItems: result)); 

            return View("Parts/Installation", result);
        }

 

I'm doin ol' plain MVC stuff but I guess it is not the right way to do this isn't it?

Is there someone who can helps me?

 

Thanks

Coordinator
Nov 29, 2012 at 7:07 PM

Not sure what you mean by refresh. Can you explain exactly the scenario you are trying to implement?

Nov 29, 2012 at 9:20 PM

Sorry, I'm new to Orchard and maybe the terms I use are not the right ones.

First, i've created a widget which displays external data in a grid. My display method looks like this:

protected override DriverResult Display(InstallationPart part, string displayType, dynamic shapeHelper) {

            List<Services.Customer.TransportModel.Installation.Installation> model =
                (List<Services.Customer.TransportModel.Installation.Installation>)(new Client().GetInstallationCollection(null, null));

            return ContentShape("Parts_Installation", () => shapeHelper.Parts_Installation(ContentItems: model)); 
        }

This use the GetInstallationCollection method to retrieve all the Data needed to fill a Kendo Grid. I'm passing the list to the template with a dynamic property named "ContentItems" This works all fine. My template's name is /Views/Part/Installation.cshtml.

Second, I've created a second widget (that i placed in FirstAside) which consists of a textbox and submit button. This button calls an action of the controller (pasted in previous post). My form looks like that.

@using (Html.BeginForm("SearchInstallation", "Installation", new { controller = "Installation", area = "MyProject.Installation" }, FormMethod.Post)) {
    @Html.AntiForgeryTokenOrchard()
   
     @Html.TextBox("textToSearch")
    <input type="submit" value=">" />  
    <br />
     
}
Up to now, no problem! My action is called perfectly... but now, when my view is returned, everything screwed up! I'm loosing everything in content zone... As you can see, my action call GetInstallationCollection again, filters the result with the FindAll method then send this data back with the view so the (grid) Widget can display filtered values.

The "refresh" means that my grid widget needs to "filter" based on search parameter in my search widget, i i'm stuck on how to do it. Since i'm learning Orchard, i'm pretty sure i've made a lot of bad code and mistakes and i'm looking foward to achieve this in a correct way ;)

I've seen a lot of differences between
     return ContentShape("Parts_Installation", () => shapeHelper.Parts_Installation(ContentItems: model));
and
    return View("Parts/Installation", result);

In the first approach, the model's Type is a shape and in the second option, my model' Type is a List. I'm really stuck in all this...

- How can an Action (plain MVC) can be used in an Orchard context?
- How can it be possible to make 2 widgets to communicate
- What am I missing

Thank you very much for your precious help.

Pat

Coordinator
Nov 30, 2012 at 5:31 PM

- How can an Action (plain MVC) can be used in an Orchard context?

Easily. Orchard is built on MVC, so it just works. Only caveats is that you need to play nice with custom routes, defining them in an IRouteProvider implementation because they are shared resources, and that you have additional capabilities to return shapes from actions and you can mark your actions as themed.

- How can it be possible to make 2 widgets to communicate

You shouldn't. Instead, both widgets should take their information from a common source.

Nov 30, 2012 at 5:58 PM

Thanks Bertrand,

Do you have an example or can you point me some doc to allow both Widgets sharing the same source?

Also, i think i've found a clue this morning, but i'm not sure how this could end. I've read this post http://orchard.codeplex.com/discussions/256646 and i've learned how i can make a widget without Driver and Parts. This way of doing things helps me a lot because i'm only using external data. I've also how to return a ShapeResult within my controller as you told me in previous post... like this:

public ActionResult SearchInstallation(string textToSearch) {

            dynamic myDisplay = _services.New.TestInfo(
                TextToDisplay: textToSearch
		        );

	        return new ShapeResult(this, myDisplay); 
}

This is perfect so i can take my searched text and pass that text to my Shape (TestInfo). The problem is that this shape I return is always displaying in the Content Zone and what i really need is display that "TextToDisplay" in the Header. Can I achieve that using Placement.info? Or do I have to specify it in my Action? Or do I have to use alternates?

Regards,

Pat

 

Coordinator
Dec 1, 2012 at 7:07 AM

Placement can target top-level zones by adding a leading slash: "/AsideSecond:5" for example.

Dec 3, 2012 at 1:40 PM

Yeah, i tried that and it doesn't seem to work. I'm probably wrong with the name
<Place TheWrongName="/AsideSecond:5"/>

What name should i write here. My shape's name is TestInfo but its a dynamic one with no part. (like this example http://orchard.codeplex.com/discussions/256646)
I guess i'll have to use a part to be able to use placement.info?

My widget's name is TestInfoWidget as defined in my Migration.cs file:
ContentDefinitionManager.AlterTypeDefinition("TestInfoWidget",
            cfg => cfg
                .WithPart("WidgetPart")
                .WithPart("CommonPart")
                .WithSetting("Stereotype", "Widget"));

And my handler looks like this:

public class TestInfoWidgetHandler : ContentHandler {

        public TestInfoWidgetHandler() {
        }

        protected override void BuildDisplayShape(BuildDisplayContext context) {
            base.BuildDisplayShape(context);

            if (context.ContentItem.ContentType == "TestInfoWidget") {
                dynamic myDisplay = context.New.TestInfo(
                    TextToDisplay: "ABCDEF"
                );

                context.Shape.Zones["Content"].Add(myDisplay);
            }

        }

        
    }

Also, you wrote about 2 widgets sharing the same source, how can I do that? It me also be a good path to explore.

Cheers,

Pat

Coordinator
Dec 3, 2012 at 7:53 PM

Right, that's not a content part. Placement is for shapes generated by content parts. In that case you just add the shape to a zone.

I don't know what more to tell you about 2 widgets sharing the same source. Your widgets are taking their data from somewhere. You'll need to be more specific.

Dec 3, 2012 at 8:10 PM

I have an API which is used to call WebServices. The method that I use is GetInstallationCollection() which returns a Generic List of Installations
List<Installation> lst = GetInstallationCollection()

This list have to be the source to every widget in my application.

- The widget "Search" (in AsideFirst) will filter that list

- The widget "Grid" (In Content) will display the List<Installation> according to the specified filter in the widget "Search"

 

Up to now the only way i managed to do this is ths way:

1) The search widget calls an action in a controller
2) This action stores filter in the HttpContext in the session
3) A handler is defined for my "Grid" widget trap the OnLoaded<InstallationPart>, get the filter in session and then calls GetInstallationCollection() to get my data from the WebService
4) The list is passed to a property of my InstallationPart (InstallationPart.ListInstallation = lst)
5) Finally Display method from the InstallationDriver looks like that:

 protected override DriverResult Display(InstallationPart part, string displayType, dynamic shapeHelper) {

            return ContentShape("Parts_Installation", () => shapeHelper.Parts_Installation(ContentPart: part));

        }

Am I doing wrong? Is there another way (better) of doing this?

I really appreciate your help Bertrand

Cheers,

Pat
 

Coordinator
Dec 3, 2012 at 8:12 PM

That sounds just fine.

Dec 3, 2012 at 9:00 PM
Edited Dec 3, 2012 at 9:02 PM

Great, i'll continue that way!

BTW, i really like Orchard. You are all doing very good with this application. We are looking to use it and we will suggest it to our clients who need a good CMS in .NET.

Thanks again,

Pat

Note: I'll son post my entire solution so someone else could benefit from my research. Is there a way to easily contribute to the knowledge base?