How to import DataTable in ERPNext form


I’m trying to include DataTable in landed_cost_voucher.js using import DataTable from ‘frappe-datatable’; however it breaks the form completely.

form_viewers.js:78 Uncaught TypeError: Cannot read property 'refresh' of undefined
    at Object.frappe.ui.form.set_viewers (form_viewers.js:78)
    at n.<anonymous> (formview.js:41)
    at n.emit (libs.min.js?ver=1534367266.0:7306)
    at n.onevent (libs.min.js?ver=1534367266.0:7307)
    at n.onpacket (libs.min.js?ver=1534367266.0:7307)
    at n.<anonymous> (libs.min.js?ver=1534367266.0:7307)
    at n.emit (libs.min.js?ver=1534367266.0:7306)
    at n.ondecoded (libs.min.js?ver=1534367266.0:7306)
    at s.<anonymous> (libs.min.js?ver=1534367266.0:7307)
    at s.n.emit (libs.min.js?ver=1534367266.0:7306)

How do I use DataTable in a form?

Share your full source!

@rmehta the full source code is not necessary to reproduce this problem. Simply add the one line “import DataTable from ‘frappe-datatable’;” anywhere in landed_cost_voucher.js and it’ll stop functioning properly.

In my case I added the line at the top:

// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
import DataTable from 'frappe-datatable';


erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
	setup: function() {
		var me = this;
		this.frm.fields_dict.purchase_receipts.grid.get_field('receipt_document').get_query =
			function (doc, cdt, cdn) {
				var d = locals[cdt][cdn]

				var filters = [
					[d.receipt_document_type, 'docstatus', '=', '1'],
					[d.receipt_document_type, 'company', '=',],

				if (d.receipt_document_type == "Purchase Invoice") {
					filters.push(["Purchase Invoice", "update_stock", "=", "1"])

				if (! frappe.msgprint(__("Please enter company first"));
				return {
					filters: filters

		this.frm.add_fetch("receipt_document", "supplier", "supplier");
		this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
		this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");


	refresh: function(frm) {
		var help_content =
			<table class="table table-bordered" style="background-color: #f9f9f9;">
						<i class="fa fa-hand-right"></i> 
							${__("Charges will be distributed proportionately based on item qty or amount, as per your selection")}
							${__("Remove item if charges is not applicable to that item")}
							${__("Charges are updated in Purchase Receipt against each item")}
							${__("Item valuation rate is recalculated considering landed cost voucher amount")}
							${__("Stock Ledger Entries and GL Entries are reposted for the selected Purchase Receipts")}

		set_field_options("landed_cost_help", help_content);

	get_items_from_purchase_receipts: function() {
		var me = this;
		if(!this.frm.doc.purchase_receipts.length) {
			frappe.msgprint(__("Please enter Purchase Receipt first"));
		} else {
				doc: me.frm.doc,
				method: "get_items_from_purchase_receipts",
				callback: function(r, rt) {

	amount: function(frm) {

	set_total_taxes_and_charges: function() {
		var total_taxes_and_charges = 0.0;
		$.each(this.frm.doc.taxes || [], function(i, d) {
			total_taxes_and_charges += flt(d.amount)
		cur_frm.set_value("total_taxes_and_charges", total_taxes_and_charges);

	set_applicable_charges_for_item: function() {
		var me = this;

		if(this.frm.doc.taxes.length) {
			var total_item_cost = 0.0;
			var based_on = this.frm.doc.distribute_charges_based_on.toLowerCase();
			$.each(this.frm.doc.items || [], function(i, d) {
				total_item_cost += flt(d[based_on])

			var total_charges = 0.0;
			$.each(this.frm.doc.items || [], function(i, item) {
				item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)			
				item.applicable_charges = flt(item.applicable_charges, precision("applicable_charges", item))
				total_charges += item.applicable_charges

			if (total_charges != this.frm.doc.total_taxes_and_charges){
				var diff = this.frm.doc.total_taxes_and_charges - flt(total_charges)
				this.frm.doc.items.slice(-1)[0].applicable_charges += diff
	distribute_charges_based_on: function (frm) {



Additionally, all my source code regarding erpnext is available on my fork GitHub - SaiFi0102/erpnext: Open Source ERP built for the web

I also tried using frappe.require(“/assets/frappe/js/lib/frappe-datatable.js”); and still the same error. Any idea?

Try this or something like it.

DataTable is awesome. Landed Cost Voucher is awesome. What are you using datatable for?

1 Like

I tried exactly that. But it makes the form throw up errors. I’m making a manual distribution table of taxes for cases when some taxes are charged in a non standard manner, however, I’ve had to use HTML templates instead of datatable since it isn’t working.

So anyways, solution please

The solution you don’t want is to save a separate copy of datatable. Let me call for reinforcements: @jhk, how’d you do it with the pond sample tool?

1 Like

Using frappe.run_serially worked for me

function load_dependencies() {

function render_page() {
    var dt = new DataTable(...);

    () => load_dependencies(),
    () => render_page()

Thanks! I’ll try it out

things have changed now, its frappe.DataTable, there’s no need to import anything, it just works out of the box now.

how to use it??
can you show a example?

can you solve?? what is the issue?

i am importing like this