Pass array as array from client JavaScript to frappe.call

We have an issue in passing an array from the client side script to the frappe server.

On the server, we have added to erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py at the end

 @frappe.whitelist()
 def count_fruit(fruit):
 	_count = 0;
 	for f in fruit:
 		_count = _count + 1
 	return { 'Count': _count }

From the client side, we then execute this through a custom script on Sales Invoice

 // count fruit
 frappe.ui.form.on("Sales Invoice", {
 	refresh: function(frm) {
 		var fruit = ["Orange", "Banana", "Lemon"];
 		frappe.call({
 			// type: 'POST',
 			method: 'erpnext.accounts.doctype.sales_invoice.sales_invoice.count_fruit',
 	 		args: { 'fruit': fruit },
 		 	callback: function(r) {
    	     	 		if (!r.exc) {
 						frappe.msgprint("Number of fruit: " + r.message.Count);
    	     			}
 			}
 		});
 	}
 });

Now, we want the fruit (or in fact the sales invoice items, just simplified to illustrate the problem; that was not a problem) to be passed as an array.

Actual result:

  • number of fruit 27 (which is the number of characters in the string)

Expected results

  • number of fruit 3 (number of elements in the array

So the issue is that the parameter is passed as a string rather than an array. How can we pass the array as an array (and not as a string)?

In your count_fruit function, put a check to see if the parameter is coming in as a string. If it is (which means its probably JSON), use json.loads to convert it to a python object and then continue with your logic.

Something like:

@frappe.whitelisted()
def count_fruit(fruit):
    # import six
    # if isinstance(value, six.string_types): # (for python 2 and 3 compatibility)
    if isinstance(s, basestring) # python 2
        fruit = json.loads(fruit)
...
2 Likes

@tundebabzy many thanks, this resolved the problem. In the sales_invoice.py, I have added at the top

import json

and adapted according to your code to

 @frappe.whitelist()
 def count_fruit(fruit):
    if isinstance(fruit, basestring):
       fruit = json.loads(fruit)
    _count = 0;
    for f in fruit:
       _count = _count + 1
    return { 'Count': _count }

Works like a charm. Thanks!

1 Like