Ethan Tremblay Ethan Tremblay - 1 month ago 6
Javascript Question

Passing data between directives and controller in Angular

I'm just working on a projet in Angular 1. The task is to do a DOM tree from json object and manipulate with it through native drag'n'drop DOM operations (with out jQuery and etc). I've been done parsing json-> dom function, loading json from server, some drag'n'drop event handlers. Now my question is how to update a json object (from this object I get a ul>li tree structure) when I done a DROP event.
Now, code


View


<div ng-controller="TreeController">
<ng-dom-tree
style="background-color: #000"
ng-model = "treeJson"
class="tree"
ng-draggable
ng-droppable>
</ng-dom-tree>
</div>



Controller


.controller('TreeController', TreeController);

TreeController.$inject = ['treeService', '$scope'];

function TreeController(treeService, $scope) {

$scope.treeJson = '';
treeService.getTree().success(function (data) {
$scope.treeJson = data;
});
}



Main directive


.directive('ngDomTree', ngDomTree)
ngDomTree.$inject = [];
function ngDomTree() {
var isEmpty = function (object) {
for (var key in object) {
return false;
}
return true;
};
function createTree(tree, list) { /*creating tree -> json to dom*/}
return {
restrict: 'E',
replace: true,
link: function (scope, elt, attrs) {
scope.$watch('treeJson', function (data) {
if (isEmpty(data))
return;
**CAN'T HANDLE DATA CHANGING HERE**
elt.append(document.createElement('ul'));
createTree(data, document.getElementsByTagName('ul')[0]);
});

}
}
}



Sup directive


.directive('ngDroppable', ngDroppable)
ngDroppable.$inject = [];
function ngDroppable() {
var parseTreeToJson = function(tree){/* dom to json */}
return {
restrict: 'A',
link: function (scope, elt, attrs) {
elt.on('mouseover', function (e) {

var droppableElt = e.target || event.target;
if (!droppableElt.classList.contains('tree__node') && !droppableElt.classList.contains('tree__branch'))
return;

droppableElt.addEventListener(
'dragover',
function (e) {

this.classList.add('navigator');
e.dataTransfer.dropEffect = 'move';
if (e.preventDefault)
e.preventDefault();
this.classList.add('over');
return false;
},
false
);

droppableElt.addEventListener(
'dragenter',
function (e) {
this.classList.add('over');
return false;
},
false
);

droppableElt.addEventListener(
'dragleave',
function (e) {
this.classList.remove('over');
this.classList.remove('navigator');
return false;
},
false
);

droppableElt.addEventListener(
'drop',
function (e) {

if (e.stopPropagation) e.stopPropagation();
this.classList.remove('over');
let item = document.getElementById(e.dataTransfer.getData('Text'));

this.appendChild(item);
item.id = '';
//updating here
scope.treeJson = parseTreeToJson(elt[0].children[0]);

return false;
},
false
);
});
}
}
}


So, In Sup directive when drop event created, and I'm reinit treeJson variable, after that I need in main directive reinitializing the tree and also in controller get new json structure from this variable, because $watch is used, but it isn't happened.

PLEASE HELP

THNKS FOR ATTENTION :)

P.S. Here it is in Plnkr.co

Answer

Since you are using native DOM, it bypasses angular's processors. You need to call scope.$digest() after changing angular's state to tell it that something changed.

droppableElt.addEventListener(
    'drop',
    function (e) {

        if (e.stopPropagation) e.stopPropagation();
        this.classList.remove('over');
        let item = document.getElementById(e.dataTransfer.getData('Text'));
        this.appendChild(item);
        item.id = '';
        scope.treeJson = parseTreeToDOM(elt[0].children[0]);
        scope.$digest();
    },
    false
);
Comments