Angular lazy tree - angularjs

I'm studying angular and trying to write treeview with dynamic load. It has some initial pre-loaded nodes, but many of them have to be loaded by demand.
I write initial tree view here jsfiddle but cannot understand how to implement lazy load.
when I click NodeLazy I want to update treeService.Nodes and this update have to refresh view
when I click any Node I want select this node by bold font and be able get selected from treeService
Sure, I could use one of existing angular tree, but I want to understand how to do this.
var app = angular.module('demo', []);
app.directive("treeView", function() {
return {
restrict: "E",
replace: true,
scope: {
t: "=src"
},
template: "<ul class='ul-node'><tree-branch ng-repeat='c in t.children' src='c'></tree-branch></ul>"
};
});
app.directive("treeBranch", function($compile) {
return {
restrict: "E",
replace: true,
scope: {
b: "=src"
},
template: "<li class='{{b.class_li}}'>{{b.name}}</li>",
controller: function($scope) {
var has_children = angular.isArray($scope.b.children);
$scope.b.class_li = has_children ? "li-node" : "li-leaf";
},
link: function(scope, element, attrs) {
var has_children = angular.isArray(scope.b.children);
if (has_children) {
element.append('<tree-view src="b"></tree-view>');
$compile(element.contents())(scope);
}
element.on("click", function(event) {
console.log("click|" + scope.b.name);
event.stopPropagation();
if (has_children) {
element.toggleClass("ul-collapsed");
}
});
}
};
});
app.service("treeService", function() {
var nodes = {
children: [
{ name: "Node_1",
children: [
{ name: "Node_1.1",
children: [{ name: "Leaf_1" }, { name: "Leaf_2" }] },
{ name: "NodeLazy_1.2", }] },
{ name: "NodeLazy_2", }]
};
return {
Nodes : nodes
};
});
app.controller("ctrl", function($scope, treeService) {
$scope.nodes = treeService.Nodes;
});

Related

function nested in directive not alerting

two questions: is it possible to access my showData() function that is located in the controller even though its not within the directive? I also have placed one in the directive but it is still not alerting? please advice on what i am doing wrong.
var myApp = angular.module('myApp', []);
myApp.controller('productController', ['$scope',
function($scope) {
$scope.product1 = {
name: 'Phone',
price: '100',
stock: true
};
$scope.product2 = {
name: 'Ipad',
price: '1000',
stock: true
};
$scope.product3 = {
name: 'Laptop',
price: '800',
stock: false
};
$scope.showData = function() {
alert("Display Data");
}
}
]);
myApp.directive('myInventory', function() {
return {
restrict: 'E',
scope: {
name: '#',
price: '#'
},
template: '{{name}} costs {{price}} <button ng-click="showData()">change cost</button>'
};
directive.link = function($scope, element) {
$scope.showData = function() {
alert("Display Data");
};
}
return directive;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<body ng-App="myApp">
<div ng-controller="productController">
<h1>{{product1.name}}</h1>
<my-inventory name="{{product1.name}}" price="{{product1.price}}"></my-inventory>
<h1>{{product2.name}}</h1>
<my-inventory name="{{product2.name}}" price="{{product2.price}}"></my-inventory>
<h1>{{product3.name}}</h1>
<my-inventory name="{{product3.name}}" price="{{product3.price}}"></my-inventory>
</div>
</body>
In your directive, you're returning too early so half of your code isn't executing.
myApp.directive('myInventory', function() {
return {
restrict: 'E',
scope: {
name: '#',
price: '#'
},
template: '{{name}} costs {{price}} <button ng-click="showData()">change cost</button>',
link: function($scope, element) {
$scope.showData = function() {
alert("Display Data");
};
}
});
It's possible for you to pass showData from the controller to the directive.
myApp.directive('myInventory', function() {
return {
restrict: 'E',
scope: {
name: '#',
price: '#',
showData: '&' // Add it to your scope like so
},
template: '{{name}} costs {{price}} <button ng-click="showData()">change cost</button>',
link: function($scope, element) {
// Don't need showData() here anymore
}
});
Call your directive with your function like so
<my-inventory show-data="showData()" name="{{ something }}" price="{{ something }}"></my-inventory>

Bind array to highcharts data part using Angular Directives

I need to bind an array of data to "data" part of highcharts which is embedded in
Angular directives but I don't know how exactly to do that.
This is my controller part which fetches data from repository:
vm.data = [];
function getVmAll(forceRefresh) {
return datacontext.esxservers.getAllWithoutPaging(forceRefresh, vm.vmAllSearchTemp)
.then(function (data) {
vm.data= data;
});
return data;
}
);
}
and here is the template which I use the controller in it:
<section class="mainbar" data-ng-controller="mbVirtualizationOverviewCtrl as vm">
<mb-virtualization-overview-donut-chart value="vm.data"></mb-virtualization-overview-donut-chart>
</section>
and the last but not least one is my directive which I use highcharts settings:
'use strict';
angular.module('app').directive('mbVirtualizationOverviewDonutChart', [
function () {
return {
restrict: "E",
templateUrl: '/app/directives/virtualizationOverview/mbVirtualizationOverviewDonutChartTemplate.html',
scope: {
value : "="
},
link: function (scope, el, attrs) {
scope.chart = Highcharts.chart(el[0], {
chart: {
type: 'pie',
},
title: {
text: scope.innerTitle
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
},
series: [{
data: undefined
}]
});
var init = true;
scope.$watch(
function () {
var chart = scope.chart;
if (init && scope.value.length > 0) {
init = false;
scope.value.forEach(function (item, index) {
chart.series[0].data.push(item);
});
}
});
}
};
}
]);

Link function of Directive is not being called

I have a scenario where I need to show a pie-chart in a popup modal (used ui-bootstrap modal). I used c3.js for my pie-chart requirement (inside a directive).
The pie-chart is not loading inside the pop up. But to my surprise when I tried to debug the issue when I opened the console it is loading. When I re-size the window it is loading.
How can i fix this issue?
'use strict';
angular.module('App')
.directive('pieChartDirective', function() {
return {
restrict: 'A',
scope: {
chartdata: '=',
},
link: function(scope, elem, attrs) {
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [
['Javascript', scope.chartdata.Javascript],
['HTML', scope.chartdata.HTML],
['Css', scope.chartdata.Css],
['Angular', scope.chartdata.Angular],
['Bootstrap', scope.chartdata.Bootstrap],
['Jquery', scope.chartdata.Jquery],
['Communication', scope.chartdata.Communication]
],
type: 'pie',
},
legend: {
show: false
},
tooltip: {
format: {
value: function(value, ratio, id, index) {
return value;
}
}
}
});
}
};
});
Html:
<div pie-chart-directive chartdata="oChartData">
<div id="chart"></div>
</div>
Are you shure, that you include your directive properly in your html code as
<div pie-chart-directive></div>
Maybe you have to change your restriction to 'E' to use your directive as a tag elment
<pie-chart-directive chartdata="myData"></pie-chart-directive>
The reason could be, that at the moment you try to generate the chart, your '#chart' div isn't yet present in the dom tree. Therefore you have to resize to trigger a new draw. Try to wait until the dom is loaded
$('#chart').ready(function() {
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [
['Javascript', scope.chartdata.Javascript],
['HTML', scope.chartdata.HTML],
['Css', scope.chartdata.Css],
['Angular', scope.chartdata.Angular],
['Bootstrap', scope.chartdata.Bootstrap],
['Jquery', scope.chartdata.Jquery],
['Communication', scope.chartdata.Communication]
],
type: 'pie',
},
legend: {
show: false
},
tooltip: {
format: {
value: function(value, ratio, id, index) {
return value;
}
}
}
});
});
I got it by giving size property:
link: function(scope, elem, attrs) {
var chart = c3.generate({
bindto: '#chart',
size: {
width:400,
height:350
},
data: {
columns: [
['Javascript', scope.chartdata.Javascript],
['HTML', scope.chartdata.HTML],
['Css', scope.chartdata.Css],
['Angular', scope.chartdata.Angular],
['Bootstrap', scope.chartdata.Bootstrap],
['Jquery', scope.chartdata.Jquery],
['Communication', scope.chartdata.Communication]
],
type: 'pie',
},
legend: {
show: false
},
tooltip: {
format: {
value: function(value, ratio, id, index) {
return value;
}
}
}
});
}

Angular material Treeview collapse/expand check box not working

Angular Material Tree view Checkbox is working fine when i try to collapse/expand first time and checked whether on Parent Node or Child Node, but it is not working when i try to Checked the different node (i.e.Child Node) on second time. I use custom directive to achieve Tree View functionality. Below is my Code.
Custom Directive
NFSModule.directive('nfsTree', function () {
return {
restrict: 'E',
replace: true,
scope: {
tree: '=source',
},
template: '<nfs-node ng-repeat="c in tree.children" cnode="c"></nfs-node>'
};
});
NFSModule.directive('nfsNode', function ($compile) {
return {
restrict: 'E',
replace: true,
scope:{
node: '=cnode'
},
template: '<li><span ng-click="toggleVisibility(node)"> {{ ( node.childrenVisibility && node.children.length ) ? "+" : "-" }}</span>' +
'<nfs-tree-checkbox ng-model="node.checked" ng-click="checkNode(node)"><span ng-bind="node.name"></span></nfs-tree-checkbox></li>', // HTML for a single node.
link: function (scope, element) {
/*
* Here we are checking that if current node has children then compiling/rendering children.
* */
if (scope.node && scope.node.children && scope.node.children.length > 0) {
scope.node.childrenVisibility = true;
var childNode = $compile('<ul ng-if="!node.childrenVisibility"><nfs-tree source="node" ></nfs-tree></ul>')(scope);
element.append(childNode);
} else {
scope.node.childrenVisibility = false;
}
},
controller: ["$scope", function ($scope) {
// This function is for just toggle the visibility of children
$scope.toggleVisibility = function (node) {
if (node.children) {
node.childrenVisibility = !node.childrenVisibility;
}
};
// Here We are marking check/un-check all the nodes.
$scope.checkNode = function (selectednode) {
if (selectednode.checked != undefined) {
var has_child = angular.isArray(selectednode.children);
if (has_child = true)
{
checkChildren(selectednode);
}
}
function checkChildren(c) {
angular.forEach(c.children, function (c) {
c.checked = selectednode.checked;
});
}
};
}]
};
});
NFSModule.directive('nfsTreeCheckbox', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
name: '#',
ngModel: '=',
ngClick: '=',
ngDisabled: '=',
label: '#'
},
template: function (elem, attr) {
return '<md-input-container class="md-inline" style="height:10px !important; margin-top:-5px; !important; margin-left:5px !important;">' +
'<md-checkbox ng-model="ngModel" ng-click="ngClick" ng-disabled="ngDisabled" aria-label="{{label}}" class="md-primary">' +
'<ng-transclude></ng-transclude>' +
' </md-checkbox>' +
'</md-input-container>'
}
};
});
$SCOPE
$scope.location = {
children:
[
{
name: 'Europe',
children: [
{
name: 'Italy',
children: [
{
name: 'Rome'
},
{ name: 'Milan' }
]
},
{ name: 'Spain' }
]
},
{
name: 'South America',
children: [
{ name: 'Brasil' },
{ name: 'Peru' }
]
}
]
};
HTML
<ul >
<nfs-tree source="location"></nfs-tree>
</ul>

angularjs ckeditor directive sometimes fails to load data from a service

I used Vojta's angularJS directive but sometimes ckeditor would fail to display the data from a service. This almost never happened on a refresh, but often happened when navigating back to the page. I was able to verify that the $render function was always calling ck.setData with the correct data, but sometimes it would not display.
It appears that the $render method was sometimes called before ckeditor was ready. I was able to resolve this by adding a listener to the instanceReady event to make sure that it was called at least once after ckeditor was ready.
ck.on('instanceReady', function() {
ck.setData(ngModel.$viewValue);
});
In the interest of completeness, here is the complete directive that I used.
//Directive to work with the ckeditor
//See http://stackoverflow.com/questions/11997246/bind-ckeditor-value-to-model-text-in-angularjs-and-rails
app.directive('ckEditor', function() {
return {
require: '?ngModel',
link: function(scope, elm, attr, ngModel) {
var ck = CKEDITOR.replace(elm[0],
{
toolbar_Full:
[
{ name: 'document', items : [] },
{ name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] },
{ name: 'editing', items : [ 'Find','Replace','-','SpellChecker', 'Scayt' ] },
{ name: 'forms', items : [] },
{ name: 'basicstyles', items : [ 'Bold','Italic','Underline','Strike','Subscript','Superscript' ] },
{ name: 'paragraph', items : [
'NumberedList','BulletedList','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock' ] },
{ name: 'links', items : [] },
{ name: 'insert', items : [ 'SpecialChar' ] },
'/',
{ name: 'styles', items : [ 'Styles','Format','Font','FontSize' ] },
{ name: 'colors', items : [] },
{ name: 'tools', items : [ 'Maximize' ] }
]
,
height: '290px',
width: '99%'
}
);
if (!ngModel) return;
//loaded didn't seem to work, but instanceReady did
//I added this because sometimes $render would call setData before the ckeditor was ready
ck.on('instanceReady', function() {
ck.setData(ngModel.$viewValue);
});
ck.on('pasteState', function() {
scope.$apply(function() {
ngModel.$setViewValue(ck.getData());
});
});
ngModel.$render = function(value) {
ck.setData(ngModel.$viewValue);
};
}
};
});
function updateModel() {
scope.$apply(function() {
if ( ck.getData().length ) {
ngModel.$setViewValue(ck.getData());
}
});
}
see full code:
return {
require: '?ngModel',
scope: true,
link: function (scope, element, attr, ngModel) {
if (!ngModel) return;
var ck = CKEDITOR.replace(element[0]);
ck.on('instanceReady', function() {
ck.setData(ngModel.$viewValue);
});
function updateModel() {
scope.$apply(function() {
if ( ck.getData().length ) {
ngModel.$setViewValue(ck.getData());
}
});
}
ck.on('pasteState', updateModel);
ck.on('change', updateModel);
ck.on('key', updateModel);
ck.on('dataReady', updateModel);
ngModel.$render = function() {
ck.setData(ngModel.$modelValue);
};
}
}
I also meet this issue
And when i found a new directive. It works well for me!!!
Please try this:
return {
require: '?ngModel',
scope: true,
link: function (scope, element, attr, ngModel) {
if (!ngModel) return;
var ck = CKEDITOR.replace(element[0]);
ck.on('instanceReady', function() {
ck.setData(ngModel.$viewValue);
});
function updateModel() {
scope.$apply(function() {
if ( ck.getData().length ) {
ngModel.$setViewValue(ck.getData());
}
});
}
ck.on('pasteState', updateModel);
ck.on('change', updateModel);
ck.on('key', updateModel);
ck.on('dataReady', updateModel);
ngModel.$render = function() {
ck.setData(ngModel.$modelValue);
};
}
};

Resources