Troubleshooting custom component builds

Firstly, Dash is amazing and using it is the first time I’ve actually been excited about doing anything on the front end. But since I’m very new to anything to do with JavaScript, I’ve been having some problems trying to create my own custom component. I’ve basically been attempting to shoehorn a react draggable component into the ExampleComponent tutorial with mixed results.

The react build appears to work - I can run npm run demo and I get a draggable component, but when I try to run the same example as a Dash app (python usage.py), the component renders but is not draggable. This has me completely stumped, and I’m not sure what tack to take trying to debug this. I’d appreciate any hints that people more versed in component development might have.

My code is in https://github.com/bennyweise/plotly_example. It’s basically a straight copy from https://github.com/mzabriskie/react-draggable with some changes to get it to build:

  • flow has been removed
  • static propTypes has been moved to Draggable.propTypes
  • children added to PropTypes so I could use it in Dash
    (None of these changes were particularly scientific - given my very limited knowledge of JavaScript, they were only done to get the build to work)

I greatly appreciate any help with this!

So rather than copying the source of react-draggable, you should try to just import the component and render it.

Draggable.js

import React from 'react';
import Draggable from 'react-draggable';

class DashDraggable extends Draggable {
  render() {
    return (
      <Draggable {...this.props}/>
    );
  }
}

DashDraggable.propTypes = {
    // fill this in with the properties 
    // that you want to make accessible to your component
    // I recommend including _all_ of the properties of draggable
    // that are JSON serializable (i.e. everything but functions)
}

For an example, see e.g. the Dash Dropdown component: https://github.com/plotly/dash-core-components/blob/master/src/components/Dropdown.react.js#L68. It basically just renders the react-select dropdown.

Thanks for the suggestion! I’ve just tried that out, and unfortunately it looks like I’m running into the same issue (the react demo handles the new DashDraggable fine, but it is no longer draggable when running it as a dash component).

I suspect (from my very limited understanding of how this works) that the problem might be with the way dash builds the virtual DOM, since the draggable component appears to check parents for a Draggable component. In the react demo, the DOM looks like Draggable -> DraggableCore -> div, whereas in the Dash version it is Draggable -> DraggableCore -> Connect(a) -> a -> div. This is completely conjecture at this point, but I think diagnosing what is happening will require me to learn a lot more about React (which is probably a good thing :slight_smile:)

Thanks for your help!

I would like to modify the “Tabs” component. I can get the boilerplate custom component to work, but not the Tabs component sourced directly from the Tabs branch in the dash-custom-components library on Github.

My process was:

(1) Create a boilerplate component but rename it to “Tabs”:

  • cd ~/custom_component_playpen
  • source activate myenv
  • conda install -c cpcloud npm
  • conda install -c conda-forge nodejs
  • npm config set strict-ssl false
  • npm install -g builder-init
  • builder-init dash-components-archetype (then follow the prompts to create ‘mycomponent’)
  • cd ~/custom_component_playpen/mycomponent/
  • mv ~/custom_component_playpen/mycomponent/src/components/ExampleComponent.react.js ~/custom_component_playpen/mycomponent/src/components/Tabs.react.js
  • sed -i ‘s/ExampleComponent/Tabs/g’ ~/custom_component_playpen/mycomponent/src/components/Tabs.react.js
  • mv ~/custom_component_playpen/mycomponent/src/components/tests/ExampleComponent.test.js ~/custom_component_playpen/mycomponent/src/components/tests/Tabs.test.js
  • sed -i ‘s/ExampleComponent/Tabs/g’ ~/custom_component_playpen/mycomponent/src/components/tests/Tabs.test.js
  • sed -i ‘s/ExampleComponent/Tabs/g’ ~/custom_component_playpen/mycomponent/src/index.js
  • sed -i ‘s/ExampleComponent/Tabs/g’ ~/custom_component_playpen/mycomponent/usage.py
  • sed -i ‘s/ExampleComponent/Tabs/g’ ~/custom_component_playpen/mycomponent/demo/Demo.react.js
  • npm install
  • python3 ./usage.py

→ success!

(Note “tests”, should read “__ tests __”, without spaces)

(2) Create a Tabs component using existing component from Github:
(following on from the steps above)

Here is a snippet from the log of the failed prepublish:

mycomponent@0.0.1 prepublish ~/custom_component_playpen/mycomponent
npm test && builder run build-dist && npm run copy-lib

mycomponent@0.0.1 test ~/custom_component_playpen/mycomponent
builder run check

[builder:config:environment] {“cwd”:“~/custom_component_playpen/mycomponent”,“dir”:“~/custom_component_playpen/mycomponent/node_modules/builder/lib”}
[builder:builder-core:start:30199] Started: run check
[builder:run] check - builder run lint && builder run test-frontend-cov
[builder:proc:start] Command: builder run lint && builder run test-frontend-cov
[builder:config:environment] {“cwd”:“~/custom_component_playpen/mycomponent”,“dir”:“~/custom_component_playpen/mycomponent/node_modules/builder/lib”}
[builder:builder-core:start:30227] Started: run lint
[builder:run] lint - eslint --fix --ignore-path .gitignore .
[builder:proc:start] Command: eslint --fix --ignore-path .gitignore .

~/custom_component_playpen/mycomponent/src/components/Tabs.react.js
1:1 error ‘ramda’ should be listed in the project’s dependencies. Run ‘npm i -S ramda’ to add it import/no-extraneous-dependencies

â 1 problem (1 error, 0 warnings)

[builder:proc:end:1] Command: eslint --fix --ignore-path .gitignore .
[builder:builder-core:end:30227] Task: run lint, Error: Command failed: sh -c eslint --fix --ignore-path .gitignore .

[builder:proc:end:1] Command: builder run lint && builder run test-frontend-cov
[builder:builder-core:end:30199] Task: run check, Error: Command failed: sh -c builder run lint && builder run test-frontend-cov

npm ERR! Test failed. See above for more details.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! mycomponent@0.0.1 prepublish: npm test && builder run build-dist && npm run copy-lib
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the mycomponent@0.0.1 prepublish script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! ~/.npm/_logs/2018-07-08T23_25_31_508Z-debug.log

Running the suggested “npm i -S ramda” does remove that particular error but the last two errors remain. Any ideas as to how I can generate the Tabs component would be greatly appreciated!

Any takers? Sorry about shamelessly bumping this to the top of the forum, but I’d be really grateful for any advice.

I created my draggable elements without react, pure JS.

Python Container for draggable object:

html.Div([                
                html.Div(            
                        'x',
                        id='close',
                        style = close_style
                        ),
                html.Div([html.Div('<',style={'display':'inline-block'},id='expand'),html.Div(dist_child,id='dist',style=side_panel_style)],
                        id='sidemenu',
                        style = expand_style
                        ),
           
                html.Div(
                'Fingerprint '+ str(id)+' ID:'+str(patients_id[id]),
                    id='mydiv'+str(id) + 'header',
                    style = fp_style
                         ),
                         
                fp_html_list  #this is the tree created 
                ],   
                id="mydiv"+str(id) , draggable = 'false',   
                style =draggable_style)

js script:

/* This script will manage fingerprints functions like drag and drop, expand menu, close... */

$(document).mousedown(function(event) {

        /* detect fingerprint header to drag and drop*/
	    $('*[id*=header]:visible').each(function() {
    		if($(this).attr('id') === event.target.id){
    			dragElement(document.getElementById(event.target.id.replace("header","")))
  			}
    
		});
		
	
});

$(document).mouseup(function(event) {

		/*remove fingerprint*/
		if(event.target.id == 'close'){
			event.target.parentNode.parentNode.removeChild(event.target.parentNode);
		}
		/*toggle side menu*/
		if(event.target.id == 'expand'){
			if (event.target.parentNode.children[1].style.display === 'none'){
				event.target.parentNode.children[1].style.display = 'inherit';	
			}
			else{
				event.target.parentNode.children[1].style.display = 'none';
			
			}
	
		}
	
});

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  elmnt.onmousedown = dragMouseDown;

  function dragMouseDown(e) {
  
    e = e || window.event;
    e.preventDefault();
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
    elmnt.style.zIndex = newdepth;
    newdepth = newdepth + 1;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  
  }

  function closeDragElement() {
    /* stop moving when mouse button is released:*/
    document.onmouseup = null;
    document.onmousemove = null;
  }
}