PDA

View Full Version : [CLOSED] Dynamicaly render panel in card layout



ingbabic
Jun 11, 2015, 3:43 PM
I have following scenario: User wants to create new object in the system. He will do it using a wizard form, where on first page he have to set a name for an object that will be created in the system and the type of that object. In Second wizard page he optionally have to enter different set of metadata depending on the type of the object he have chosen on the first page. So far I have done something like this:


@(
Html.X().Window().Title("Create object").Width(500).Height(400).Layout(LayoutType.Fit)
.Items
(
Html.X().Panel().ID("WizardPanel").BodyPadding(15).Layout(LayoutType.Card).ActiveIn dex(0)
.Items
(
Html.X().FormPanel().ID("Panel1").Border(false).Header(false).Layout(LayoutType.VB ox)
.Items
(
Html.X().TextField().ID("objName").FieldLabel("Name:").LabelWidth(40).Width(300),
Html.X().ComboBox().ID("objType").FieldLabel("Type:").LabelWidth(40).Width(300)
.Items(new ListItem[] { new ListItem("Invoice", "invoice"), new ListItem("Contract", "contract"), new ListItem("Instructions", "instructions")})
.SelectedItems(new ListItem() { Value = "invoice" }),
)
,
Html.X().Panel().ID("Panel2").Border(false).Header(false).ItemsFromPartial("~/Views/Properties/_Properties.cshtml").Layout(LayoutType.Fit).AutoScroll(true)
)
.Buttons
(
Html.X().Button().ID("btnPrev").Text("Prev").Disabled(true).Icon(Icon.PreviousGreen).DirectEv ents(de =>
{
de.Click.Url = Url.Action("Prev_Click");
de.Click.ExtraParams.Add(new Parameter("index", "#{WizardPanel}.items.indexOf(#{WizardPanel}.layout .activeItem)", ParameterMode.Raw));
}),
Html.X().Button().ID("btnNext").Text("Next").Icon(Icon.NextGreen).DirectEvents(de =>
{
de.Click.Url = Url.Action("Next_Click");
de.Click.ExtraParams.Add(new Parameter("index", "#{WizardPanel}.items.indexOf(#{WizardPanel}.layout .activeItem)", ParameterMode.Raw));
}),
Html.X().Button().ID("btnFinish").Text("Finish").Icon(Icon.Accept).DirectEvents(de =>
{
de.Click.Url = Url.Action("Finish_Click");
de.Click.ExtraParams.Add(new Parameter("typeName", "#{Panel1}.getForm().getFieldValues(false)", ParameterMode.Raw));
de.Click.ExtraParams.Add(new Parameter("properties", "#{Panel2}.down('form').getForm().getFieldValues(tr ue)", ParameterMode.Raw));
de.Click.Success = @"this.up('window').close();";
})
)
)
)


Partial view _Properties is using ViewData["objType"], set in advance to "invoice" to render itself and everything is correct when user does not change object type to create. But when user changes it (combobox), I should somehow make partial view in Panel2 to re-render itself with information from combobox (selected item). That does not mean that when user changes selection in combobox, that we have to automatically switch to re-rendered second page. In fact user can select for example Contract and then back again to Invoice and on pressing Next nothing should change on second page. More over user must not press Next button at all, he can immidiatelly go to Finish, after he enters name and the type of the object. Source of _Properties I did not put here since it is irrelevant (as I said it is doing correctly it's job as long as ViewData have valid information). I tried different approaches but none of them seem to work. I am aware that ideal event for doing something is on Click of Next button, but I don't know what to do there (currently it is just changing page).


public ActionResult Next_Click(int index)
{
this.GetCmp<Panel>("WizardPanel").ActiveIndex = index + 1;
this.CheckButtons(index + 1);
return this.Direct();
}


Please advise me how could I do this.

Daniil
Jun 11, 2015, 8:38 PM
Hi @ingbabic,


But when user changes it (combobox), I should somehow make partial view in Panel2 to re-render itself with information from combobox (selected item).

.ItemsFromPartial() is not possible to re-render without re-rendering the entire view, but you can try to load the Panel2's content via an AJAX request.

For example,
http://mvc2.ext.net/#/Dynamic_Partial_Rendering/Partial_Items

When you click menu items, the content of the right panel is loaded on the fly via AJAX. My suggestion is to try that in your scenario.

ingbabic
Jun 12, 2015, 6:55 AM
Hi Daniil
So if I understand you correctly I should do this on combo select event? Maybe you didn't notice it, but actually it is not necessary to do it on select change in combo box, because user can play with combobox which does not mean that we should do any action on it, especially because that action is not visibile (it is on next card). Even user can press Finish without going to next page at all, so all that work would be worthless. I thought it is better to do it on press Next in wizard. Is it feasible?

Daniil
Jun 15, 2015, 1:14 PM
Sorry, it looks I don't comprehend the scenario. If you provide a test case to reproduce the scenario, I would do my best to be more helpful.

ingbabic
Jun 16, 2015, 11:35 AM
Ok, take a look at this:

Index.cshtml


@{
ViewBag.Title = "Create object";
}

<h2>Create object</h2>

@Html.X().ResourceManager()

@(
Html.X().Window().Title("Create object").Width(500).Height(400).Layout(LayoutType.Fit)
.Items
(
Html.X().Panel().ID("WizardPanel").BodyPadding(15).Layout(LayoutType.Card).ActiveIn dex(0)
.Items
(
Html.X().FormPanel().ID("Panel1").Border(false).Header(false).Layout(LayoutType.VB ox)
.Items
(
Html.X().TextField().ID("objName").FieldLabel("Name:").LabelWidth(40).Width(300),
Html.X().ComboBox().ID("objType").FieldLabel("Type:").LabelWidth(40).Width(300)
.Items(new ListItem[] { new ListItem("Invoice", "invoice"), new ListItem("Contract", "contract"), new ListItem("Instructions", "instructions")})
.SelectedItems(new ListItem() { Value = ViewData["objType"].ToString() })
.DirectEvents(de =>
{
de.Select.Url = Url.Action("ChangeType");
de.Select.ExtraParams.Add(new Parameter("selectedType", "records[0].data[this.valueField]", ParameterMode.Raw));
})
)
,
Html.X().Panel().ID("Panel2").Border(false).Header(false).ItemsFromPartial("_Properties", null, ViewData).Layout(LayoutType.Fit).AutoScroll(true)
)
.Buttons
(
Html.X().Button().ID("btnPrev").Text("Prev").Disabled(true).Icon(Icon.PreviousGreen).DirectEv ents(de =>
{
de.Click.Url = Url.Action("Prev_Click");
de.Click.ExtraParams.Add(new Parameter("index", "#{WizardPanel}.items.indexOf(#{WizardPanel}.layout .activeItem)", ParameterMode.Raw));
}),
Html.X().Button().ID("btnNext").Text("Next").Icon(Icon.NextGreen).DirectEvents(de =>
{
de.Click.Url = Url.Action("Next_Click");
de.Click.ExtraParams.Add(new Parameter("index", "#{WizardPanel}.items.indexOf(#{WizardPanel}.layout .activeItem)", ParameterMode.Raw));
}),
Html.X().Button().ID("btnFinish").Text("Finish").Icon(Icon.Accept).DirectEvents(de =>
{
de.Click.Url = Url.Action("Finish_Click");
de.Click.Success = @"this.up('window').close();";
})
)
)
)


_Properties.cshtml


@Html.X().Label().Text(ViewData["objType"].ToString()).Icon(Icon.ApplicationFormAdd)


Controler


public ActionResult Index()
{
ViewData["objType"] = "contract";
return View();
}

public ActionResult Next_Click(int index)
{
this.GetCmp<Panel>("WizardPanel").ActiveIndex = index + 1;
this.CheckButtons(index + 1);
return this.Direct();
}

public ActionResult Prev_Click(int index)
{
this.GetCmp<Panel>("WizardPanel").ActiveIndex = index - 1;
this.CheckButtons(index - 1);
return this.Direct();
}

private void CheckButtons(int index)
{
this.GetCmp<Button>("btnNext").Disabled = index == 1;
this.GetCmp<Button>("btnPrev").Disabled = index == 0;
}

public ActionResult ChangeType(string selectedType)
{
ViewData["objType"] = selectedType;
return this.Direct();
}

public ActionResult Finish_Click(string formValues)
{
return this.Direct();
}


I need when I click on Next button that next card is shown updated with selected item in combobox. There are following constraints:

I need to use partial view, because it consist some logic which has to be reused
I'd like not to do any special action on combobox select event because user can do different selections many times and at last he can press finish without going to next card at all.

Daniil
Jun 17, 2015, 8:32 AM
Thank you for the test case.

I would recommend to replace Panel2 with this Container.

Html.X().Container()
.Layout(LayoutType.Fit)
.AutoScroll(true)
.Loader(Html.X().ComponentLoader()
.Mode(LoadMode.Script)
.Url(Url.Action("GetPartialView"))
.ReloadOnEvent(true)
.TriggerEvent("show")
.Params(parameters =>
{
parameters.Add(new Parameter("containerId", "this.id", ParameterMode.Raw));
parameters.Add(new Parameter("comboBoxValue", "App.objType.getValue()", ParameterMode.Raw));
})
)
and define this controller action:

public ActionResult GetPartialView(string containerId, string comboBoxValue)
{
Ext.Net.MVC.PartialViewResult r = new Ext.Net.MVC.PartialViewResult
{
ViewName = "_Properties",
RenderMode = RenderMode.AddTo,
ClearContainer = true,
ContainerId = containerId,
WrapByScriptTag = false
};

r.ViewData["objType"] = comboBoxValue;

return r;
}

ingbabic
Jun 17, 2015, 9:24 AM
Great! Thanks!