dynamic multi-select from API call

Hello

    what i'm trying to achieve here is to make an API call and use the retrieved values to generate a dynamic multi-select field and be able to save selected options. I have used HOWTO: Have a dropdown field that get's it's options from a function as a start point with no success. This is what i did:

1- created a new dropdown from dropdown editor named test_users_list to attach it to the multi-select field below. The reason i created this list was b/c when you create a multi-select field from studio it can't be empty and i didn't want to use any of the existing ones.

2- created a new multi-select field on campaigns (using dropdown list from step 1) that created the following file

custom/Extension/modules/Campaigns/Ext/Vardefs/sugarfield_test_users_c.php

3- inside that file it contained

<?php
// created: 2017-10-19 03:23:07

$dictionary['Campaign']['fields']['test_users_c']['labelValue']='test users';
$dictionary['Campaign']['fields']['test_users_c']['dependency']='';
$dictionary['Campaign']['fields']['test_users_c']['visibility_grid']='';

?>

4- proceeded to create the function as advised on the HOWTO and my file ended up like this

<?php
// created: 2017-10-19 03:23:07
function getUsers() {
$ch = curl_init('https://jsonplaceholder.typicode.com/users');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$userss = json_decode($result, true);

$userList = array();
$userList['']='';
foreach ($userss as $i => $userx) {
$userList[$userss[$i]['username']]=$userss[$i]['name'];
}

return $userList;
}
unset($dictionary['Campaign']['fields']['test_users_c']['options']);
$dictionary['Campaign']['fields']['test_users_c']['function']='getUsers';
$dictionary['Campaign']['fields']['test_users_c']['labelValue']='test users';
$dictionary['Campaign']['fields']['test_users_c']['dependency']='';
$dictionary['Campaign']['fields']['test_users_c']['visibility_grid']='';

?>

Went to campaigns module, edited a campaign and the field is empty the array list wasn't created

empty multi-select

One thing that i noticed is that i didn't have 

$dictionary['Campaign']['fields']['test_users_c']['options']

to unset as advised on the HOWTO. I tried removing it with same results.

This HOWTO seems to be for an older version should still work for Ent 7.9.2, what could i be missing?

P.S. the API Call and the Array list do work i tested them separately this is how it looks the array list that should populate the multi-select

Array
(
[] =>
[Bret] => Leanne Graham
[Antonette] => Ervin Howell
[Samantha] => Clementine Bauch
[Karianne] => Patricia Lebsack
[Kamren] => Chelsey Dietrich
[Leopoldo_Corkery] => Mrs. Dennis Schulist
[Elwyn.Skiles] => Kurtis Weissnat
[Maxime_Nienow] => Nicholas Runolfsdottir V
[Delphine] => Glenna Reichert
[Moriah.Stanton] => Clementina DuBuque
)

please advise

Sergio

  •   I have not done this but, as you noticed, the HowTo that you are referring to is very old (2011) which suggests it is a 6.x solution. Version 7.x is very different.

    You will want to look at the enum field type: <mysugar>/clients/base/fields/enum/enum.js to see how the values are set for the dropdown options and you will want to either extend that field type for your module or create your own field type for that particular multi-select.

    Note that the getAppListStrings is used at multiple points in the enum for building the list, displaying, and saving values. So you'll need to make sure that your values pass all the checks and balances for dropdowns. As you may have noticed, if you have a value in the database that is no longer in the dropdown's app_list_strings (like a legacy value) it won't display at all in the front end. (Have a way to mark dropdown values as legacy ) so you will need to make sure your dynamic dropdown values exist when you load your list view, record view etc.

    I hope this helps you move forward and I look forward to seeing how you solve this challenge.

    FrancescaS

  • Hello Sergio, 

    I've done something similar. In my case, The users from Sugar have a Sales Channel property (A multiselect field, so they can have different Sales Channels).

    Then, when I'm creating an opportunity, there is a Sales Channel dropdown field that will populate ONLY the values from the assigned user, and everytime the user gets changed, the function will retreive the proper Sales Channels.

    If the assigned user has only one sales channel , then it will be selected by default.

    ({
    extendsFrom: 'OpportunitiesCreateView',
    initialize: function (options) {
    this._super('initialize', [options]);
    this._filterSalesChannelDropdown();
    this.model.on('change:assigned_user_id', this._filterSalesChannelDropdown, this);
    },

    _renderHtml: function(options) {

    this._super("_renderHtml", [options]);
    },

    _filterSalesChannelDropdown: function() {
    //debugger;
    var self = this;
    var userBean = app.data.createBean('Users', {id:self.model.get("assigned_user_id")});
    var saleschannel_list = app.lang.getAppListStrings('Sales_Channel_list');

    var request = userBean.fetch({

    success: _.bind(function(data) {
    if (userBean.get("sales_channel_c")){
    inString = (userBean.get("sales_channel_c")).toString();
    var dd_values = {};
    var dd_array = {};
    var array_count = 0;
    _.each(saleschannel_list, function(value, key) {
    //console.log(key, value);
    if(key === ""){
    dd_values[key] = value;
    }else if(inString.search(key)==-1){
    delete dd_values[key];
    }else{
    dd_values[key] = value;
    dd_array[array_count] = key;
    array_count = array_count+1;
    }
    });
    self.model.fields['sales_channel_c'].options = dd_values;
    if (Object.keys(dd_values).length == 2){
    self.model.set('sales_channel_c', dd_array[0]);
    }
    }
    },this),
    });

    },

    _dispose: function() {
    this._super('_dispose', []);
    }

    })

    Hope this helps.

    Angel Mtz.

  • Angel Martinez

       thank you for your response i've been reading about this after Francesca Shiekh showed me the way, now my question for you is, where do you put that code? did you updated enum.js or created a new file? if you created a new file where was it and is it a js or php file?

  • Looks like Angel took a different approach and is using the create view controller.

    <mysugar>/custom/modules/<your module>/clients/base/views/create/create.js

    He is building an array of dropdown values and setting the field's options to that array:

    self.model.fields['sales_channel_c'].options = dd_values; 

    That works but what he's doing is just filtering the existing dropdown to include only a subset of values, as opposed to building the list dynamically from scratch - which I think is what you were asking about. He is removing from view the values that he doesn't want the user to see when a new record is created, but whatever value the user does set, it exists in the language's app_list_strings array so it will display correctly.

    You don't have a set dropdown list that you are filtering, do you?

     

    FrancescaS

  • That's correct i do want to start from scratch, and i do have an idea of what to do but needed to know where to start.

    i have found two possible ways to implement this

    Custom Enum (dropdown) Fields and Select2 Fields 

    and your implementation

    Dynamic Multi-select on QLI will not store selected value/s, though it says it saved.Dynamic Multi-select on QLI will not store selected value/s, though it says it saved.

    On both questions you both start with 

    ({

      extendsFrom: 'EnumField',

      initialize: function(opts) {

        this._super('initialize', [opts]);

    which I assumed it was where i needed to start too but in your question it didn't say where to save it.

    I liked Paul Carlton's implementation he did write a detailed step by step but i got stuck at step 1 (even though it may not be what i'm looking for it was a good howto to start playing with)

    You MUST extend from 'EnumField' and this is placed in either: /custom/clients/base/fields/ or /custom/modules/<module>/clients/base/fields/

    because my sugar installation doesn't have any of those folders therefore i wasn't sure where to create the file, and since i don't have much experience developing in sugar don't know if i forcefully create the folders will work or not therefore i got stuck.

  • We all create folders in custom, that is the correct way to do things, just make sure the permissions are set properly and that you run a QRR after each change.

    I'll have to spend some time with Paul Carlton's post, looks very interesting.

    My implementation of the QLI is specific to Quotes, which work a little differently from other modules, so, especially if you're new to Sugar, stick with Paul's tutorial and see where you can from there.

    Best of luck!

    FrancescaS

  • hello Francesca Shiekh,

       just to give u an update and ask a question. I tried to use Paul's post but i just couldn't make it work (i'll keep trying), i started searching for an 'easier' way to do this and i found it but there's a catch... I need to do a QRR to pull the latest data that has been added therefore either i create a daily scheduled QRR or i won't be seeing newer data

    How to display account names dynamically on a dropdown field?

       does your implementation have to deal with the same or does it truly pulls latest data without a QRR?

    Sergio

  • The need for QRR suggests that you are updating your language file but not the corresponding file in the cache.

    There are two ways to trigger the update of a cache file: remove that particular cache file or QRR (which updates it). Perhaps you can find a way to remove the cached file when your language file is updated. that way you force a rebuild of that cache file.

    My implementation does not need to do that because I'm only changing what is displayed by removing some of the options, I'm not adding any.

    I would caution against a scheduled QRR since it does cause disruption to users when you QRR.

    HTH
    FrancescaS

  • I made created a new rest endpoint which returns all the dynamic values when a dependant dropdown field gets changed. you can get the values like this

    $module = "Calls"//the module
    $field = "subtopic_c"; //the child enum field that you want to update
    $parent_value = "events"; //the selected value of the parent field
    $bean = BeanFactory::newBean($module);
    return $bean->field_defs[$field]['visibility_grid']["values"][$parent_value];