Dynamically populate drop down list

Jul 31, 2013 at 11:22 AM
I have a dialog which contains two drop down lists on it. When user select an option from first drop down list, I want the values in the second drop down list to be populated dynamically as per the value selected in the first one.

I wonder if NOF supports this kind of scenario.
Jul 31, 2013 at 2:32 PM
Yes, this is possible.

From the manual in section 2.3.5.4.4. How to specify a set of choices for a parameter

It is possible to specify a set of choices for a parameter based on the selection(s) already made for another parameter or parameters - for example to vary the available choices for a Province property based on the Country selected, as shown below:
public Address CreateAddress(string line1 As String, Country country, Province province)
  
public IList<Province> Choices2CreateAddress(Country country) { 
    if (country == null) { return new List<Province>; }
    var q = from p in Container.Instances<Province>()
            where p.Country.Id == countryOfResidence.Id
            select p
    return q.ToList();
}
In the above example code the numeral 2 in Choices2CreateAddress indicates that this method provides the choices for parameter 2 in the CreateAddress method - which is the province parameter (parameters are numbered from zero). However, the selected value for the country parameter (in this example the Country class is assumed to be a Bounded set) is passed in to this Choices method. Note also that the code guards against being called with a null value, returning an empty set of choices in this case (it could also return a default set of choices).
Aug 1, 2013 at 8:30 AM
Thanks. I've tried that. When I select the option from first drop down list, it does populate 2nd drop down list dynamically. However, after it populates the 2nd drop down list, the value selected in first drop down list is reset to null.

The first DDL is called "relative", it has two items, When I selected relative 1, it populates 2nd drop down list 'Payment Method'. But the selected item in Relative DDL is reset back to NULL.

Any suggestion on that? The code for this action is below.
 public virtual Individualisation CreateIndividualisation(ICustomer relative, IPaymentMethod paymentMethod, IEnumerable<Allowance> allowances)
        {
            var individualisation = Container.NewTransientInstance<Individualisation>();
            individualisation.Relative = relative;
            individualisation.AssociatedClaim = this;
            individualisation.AssociatedAllowances = this.Allowances;

            return individualisation;
        }

        public IList<ICustomer> Choices0CreateIndividualisation()
        {
            var allChildren = GetRelatedCustomers(Customers.Api.Api.DependentType.Caree);
            return allChildren;
        }

        public IList<IPaymentMethod> Choices1CreateIndividualisation(ICustomer relative)
        {
            if (relative == null) { return new List<IPaymentMethod>(); }
            var payee = (IPayee)relative;
            var pms =  PaymentService.FindPaymentMethods(payee).Where(p => p.PaymentChannelValue == 3 || p.PaymentChannelValue == 2 || p.PaymentChannelValue == 1).ToList();
            return pms;
        }
Coordinator
Aug 1, 2013 at 10:01 AM
I can't see anything immediately wrong here. I note that you have a third param of type IEnumerable. If you (temporarily) removed that param, do you still get the same issue (I am just wondering if there is some complex iteraction going on there).

Secondly, put breakpoints on all the choices methods and check exactly when they are being called and with what values.

I assume you have no Default, Validate or other associated methods here .
Aug 1, 2013 at 10:29 AM
The same behavior after I removed third param of type IEnumerable. I then put the break points into different choice methods. Here is what my observation:

Choices0CreateIndividualisation() method is called when first time the dialog is loading, which is normal.

When I select item from first DDL 'Relative', Choices0CreateIndividualisation() method is called again. That explains why value is set to null for first DDL, as it populate the first DDL again.

I think the framework should not let Choices0CreateIndividualisation() method being called when user selects item from DDL.

I have no default, validate or other associated methods here.
Coordinator
Aug 1, 2013 at 11:08 AM
When I select item from first DDL 'Relative', Choices0CreateIndividualisation() method is called again. That explains why value is set to null for first DDL, as it populate the first DDL again.
I don't understand your second sentence. Yes, the Choices0 method is called again (and that is the designed behaviour) - but why would that reset the value to null? I just tried the following equivalent snippet and it works just fine:
        public void DoSomething(string param1, string param2)
        {

        }

        public IList<string> Choices0DoSomething()
        {
            return new string[] {"p1", "p2"};
        }

        public IList<string> Choices1DoSomething(string param1)
        {
            if (param1 == "p1") return new string[] { "p3", "p4" };
            return new string[] { "p5", "p6" };
        } 
Aug 1, 2013 at 1:00 PM
What I meant for the 2nd sentence is :

In first DDL, I picked up one relative , let's say relative 1, it will populate 2nd DDL with payment methods related to relative 1. However, in the first DDL, it has blank value selected. I would expect to see 'relative 1' still selected.

I tried your example, it worked perfect. When I pick up 'p1', it shows 'p3', 'p4' on 2nd DDL, and p1 remains selected in first DDL.

Maybe it's to do with parameter types.
Aug 20, 2013 at 7:41 AM
hi guys,

I have the similar issue. My code snippet is here:
        public Case CreateTicket(ServiceOrder serviceOrder, ServiceDetail serviceDetail, Severity severity, CaseType caseType)
        {
            Case newCase = Container.NewTransientInstance<Case>();
            newCase.ServiceDetail = serviceDetail;
            newCase.Severity = severity;
            newCase.CaseType = caseType;
            return newCase;
        }
        public IList<ServiceOrder> Choices0CreateTicket()
        {
            List<ServiceOrder> sos = Container.Instances<ServiceOrder>().ToList();
            return sos;
        }
        public IList<ServiceDetail> Choices1CreateTicket(ServiceOrder serviceOrder)
        {
            return assetRepository.GetServiceDetail(serviceOrder);
        }
        public IList<Severity> Choices2CreateTicket(ServiceDetail serviceDetail)
        {
            if (serviceDetail != null)
            {
                return serviceDetail.SLAs.Select(x => x.Severity).Distinct().ToList();
            }
            return new List<Severity>();
        }
        public IList<CaseType> Choices3CreateTicket(Severity severity)
        {
            if (severity != null)
            {
                return (from sla in Container.Instances<SLA>()
                        where sla.Severity.Id == severity.Id
                        select sla.CaseType).Distinct().ToList();
            }
            return new List<CaseType>();
        }
when i have selected the ServiceOrder then the ServiceDetails are populated and interestingly the ServiceOrder is set to null/blank in the drop down box. same is happening for the rest boxes.

Please tell me that is it happening due to Object Type Parameter? and what to do to overcome this issue?

thanks in advance.

Happy Coding.
Coordinator
Aug 20, 2013 at 8:15 AM
I have just tried another example using two reference object params:
        public void TestDynamicChoices(Foo f1, Foo f2) { ...}

        public IList<Foo> Choices0TestDynamicChoices()
        {
            return AllFoos();
        }

        public IList<Foo> Choices1TestDynamicChoices(Foo f1)
        {
            if (f1 == null) return new List<Foo>();
            return AllFoos().Where(...).ToList();
        }
And it worked correctly. I suggest you work back to a simpler version of your method (1 param, then 2 params and so on) and identify at what point the behaviour becomes incorrect. Then post the code for the last one that is correct and the first one (with minimal change) where it isn't.