So i have the following directive:
angular.module('Division').directive('divisionChart', function (divisionListService) {
return {
restrict: 'E',
templateUrl: 'js/helpers/Division/directives/division-chart/division-chart.html',
replace: true,
link: function (scope, element, attr) {
function createChart() {
divisionListService.getList().then(function (result) {
var rows = [];
result.forEach(function (x) {
rows.push({
"c": [
{"v": x.id, "f": x.name},
{"v": x.parent_id >= 0 ? x.parent_id : ''}
]
})
});
var data = {
"cols": [
{"label": "Name", "pattern": "", "type": "string"},
{"label": "Manager", "pattern": "", "type": "string"},
{"label": "ToolTip", "pattern": "", "type": "string"}
],
"rows": rows
};
scope.chartObject = {
type: "OrgChart",
data: data
};
});
}
// Instantiate and draw our chart, passing in some options.
jQuery(document).ready(function () {
createChart();
});
}
}
});
And the following html:
<div class="col-xs-12">
<div id="chart_div" google-chart chart="chartObject"></div>
</div>
The data generated can be fairly large when dealing with greater organizations.
Which makes my diagram leave the screen like the image below shows:
I have tried fixing the issue by setting the width:100% however it does not seem to do anything.
So my question is how can fix this issue?
Google chart does not support it.
I would suggest you to use getorgchart instead
Related
I have JSON data source with nested obvar
jsonData = {
"block":[
{"name": "Block 1. Social Work",
"subblock": [{
"name": "Block 1.1. Student Org (SO)",
"paragraph": [
{
"name": "Head of SO",
"score": "10,00"
}, {
"name": "Head of Group" ,
"score": "9, 00 "
}]
}]
}]
};
Wher block.name = table caption, subblock.name =
var subbl_content=document.createElement("th");
subbl_content.colSpan=4;
subbl_content.innerHTML=jsonData[0].block[0].subblock[0].name;
paragraph = table content. I try to place it to DataTable in the following way
$(document).ready(function() {
.....
$('#example').DataTable(
{
data: jsonData,
columns: [
{ data: 'block[0].subblock[0].paragraph[0].name' },
{ data: 'block[0].subblock[0].paragraph[0].score' }
]
});
}) ;
It would seem that must work but as a result i have in one Cell next value Head of SOiHead of Group. But when i some change data like
$('#example').DataTable(
{
data: jsonData.block[0].subblock[0].paragraph,
columns: [
{ data: 'name' },
{ data: 'score' }
]
});
All works. Is it normal or are there other methods of solution?
I have a pretty simple Kendo Grid that displays a list of data with titles and is conditionally editable on a field. This is rendered and attached to the DOM using JQuery in a function that is called in the "show" action of a Kendo View.
The issue is that either the data does not render or the grid column headers don't render every time I load the page. It's always one or the other, the only time it renders properly is if I refire the function that attaches it as I occasionally do when the state of the page changes.
Here's where I attach it to the page:
form.find("#approvals").kendoGrid({
columns: [
{ title: "Service", field: "PartDescription" },
{ title: "Component", field: "Component", width: "250px" },
{ title: "Status Last Modified", width: "250px", template: "#= kendo.toString(StatusModifiedDate, 'g') #", },
{ title: "Status", field: "Status", width: "135px", editor: statusDropDownEditor }
],
editable: modifyState,
edit: function (e) {
if (e.container.find("input").attr("name") !== "Status") {
this.closeCell();
}
}
});
This comes from the function that is fired when the Kendo View is shown.
The issue is that either the data does not render or the grid column
headers don't render every time I load the page.
Without knowing what "form" is in your js code, try using this to make sure it loads at the 'correct' time. Please feel free to tinker the gridData variable to match your code and preg_replace the fields for your fields.
<!DOCTYPE html>
<html>
<head>
<script src="https://kendo.cdn.telerik.com/2017.1.118/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2017.1.118/js/kendo.all.min.js"></script>
<meta charset="utf-8"/>
<title>Kendo UI Snippet</title>
</head>
<body id="theBod">
<div id="approvals"></div>
<script type="text/javascript">
$(function () { // the dom is ready for jquery parsing
var gridData = [{
"Name": "daya",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}, {
"Name": "siva",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}, {
"Name": "sivadaya",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}, {
"Name": "dayasiva",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}];
var form = $("#theBod");
var foundForm = $(form).find("#approvals");
if (typeof (foundForm) != "undefined") {
// process grid component
var grid = $(foundForm).kendoGrid({
dataSource: {
data: gridData,
schema: {
model: {
fields: {
Name: { type: "string" },
Role: { type: "string" }
}
}
},
pageSize: 10,
},
editable: true,
sortable: true,
columns: [
{
field: "Name",
title: "Name",
},
{
field: "Role",
title: "TheRole"
}
]
});
} else {
alert('no dom element located');
}
});
</script>
</body>
</html>
I have added a jsBin file for you.
The jsBin was not saved correctly, apologies.
I'm trying to build a widget to render arbitrary data (javascript object) on ui. And the schema of the data is defined by a json schema file. And the model must be two-way binding since I want use this widget to input/display data.
Is directive the right way to do this? Is there anyone can give me some clue to achieve this?
Yes, a directive is the right way. You can see that the angular-schema-form mentioned in the comments is using directives.
If you'd like to create your own directive. Please have look at the demo below or this jsfiddle.
The example with the comments is probably not the best because there you wouldn't need the two-way binding of the data.
But it should give you an idea how this could work.
How does the code work?
It loops over schema.items.properties and creates a template with ng-model / ng-restrict and all bindings added to the template.
After the loop is done the $compile service is adding the current scope to the template.
Replace the html with the compiled template.
The demo is probably pretty basic compared to the angular-schema-form code but it's easier to understand and easier to modifiy to your needs.
angular.module('demoApp', [])
.controller('mainController', MainController)
.directive('awDisplayJsonView', DisplayJsonView)
.directive('awDateParser', DateParser);
/**
* Translates unix time stamp into readable dates
* from model/view & view/model
*/
function DateParser() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function(data) {
//convert data from view format to model format
return new Date(data).getTime(); //converted
});
ngModelController.$formatters.push(function(data) {
//convert data from model format to view format
return new Date(parseInt(data)).toUTCString(); //converted return UTC
});
}
}
}
function MainController() {
angular.extend(this, {
/*jsonView: {
"text": { // name of model
type: "input",
label: "Two way binded input",
}
},*/
jsonModel: [{
"id": 1,
"name": "Test User",
"text": "I am a comment.",
"date": "1435427542904",
}, {
"id": 2,
"name": "Antother User",
"text": "I am the second comment.",
"date": "1435427605064",
}],
jsonSchema: {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Comments",
"type": "array",
"items": {
"title": "Comment",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a comment.",
"type": "number",
"format": "hidden" // not sure if this is the right place
},
"name": {
"title": "Name",
"type": "string"
},
"text": {
"title": "Comment",
"type": "string"
},
"date": {
"title": "Date (format y/m/d hh:mm:ss GMT)",
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"name",
"text"]
}
}
});
}
function DisplayJsonView($compile) {
var templatesObj = {
string: function (hidden) {
return $('<input/>')
.attr('type', hidden)
.addClass('form-control');
},
checkbox: function (hidden) {
return $('<input/>')
.attr('type', hidden || 'checkbox')
.addClass('form-control');
},
number: function(hidden) {
return $('<input/>')
.attr('type', hidden)
.addClass('form-control');
}
};
function render(schema, model, index) {
var outTemplate = $(document.createDocumentFragment()),
tempTmpl, hidden; // temporary template, hidden input
angular.forEach(schema.items.properties, function (prop, key) {
//console.log(key, prop.type, prop.format, templatesObj[prop.type]);
hidden = prop.format == 'hidden'? 'hidden': null;
tempTmpl = templatesObj[prop.type](hidden); // get template based on type
tempTmpl.attr({
'ng-model':
'model[' + index + '].' + key, // add current model
'ng-required': schema.items.required.indexOf(key) != -1 // check if it is required
});
if (prop.format == 'date-time')
tempTmpl.attr('aw-date-parser', ''); // add directive if we have a date
outTemplate.append($('<div/>').addClass('form-group')
.append(!hidden ? $('<label/>').text(prop.title || key) : null) //add label if not hidden
.append(tempTmpl));
});
//console.log(model, outTemplate);
return outTemplate;
}
return {
restrict: 'EA',
scope: {
//view: '=', // angular schema form does implement this
model: '=',
schema: '='
},
template: '<div>{{schema |json:2}}</div>',
link: function (scope, element, attrs) {
var out = $('<form/>');
angular.forEach(scope.model, function(item, index) {
//console.log(item);
out.append(render(scope.schema, item, index));
});
var compiled = $compile(out)(scope);
//console.log(scope.model, scope.schema);
element.replaceWith(compiled);
}
};
}
DisplayJsonView.$inject = ['$compile'];
body {
padding: 0.5em;
}
.form-group {
padding-bottom: 0.25em;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.js"></script>
<div ng-app="demoApp" ng-controller="mainController as ctrl">
<h3>Comments list with schema json directive</h3>
<form name="form" aw-display-json-view="" data-model="ctrl.jsonModel" data-schema="ctrl.jsonSchema" ng-cloak=""></form>
<div ng-cloak>
{{form|json}}
{{ctrl.jsonModel}}
</div>
</div>
I am trying to filter results using Typeahead.js. I can currently filter the results using a field called activity_title. This works fine.
How can I filter my results by a second value? In this case, I would like to select only the results that have a certain value for activity_level. I need to set this when the typeahead is initialised rather than hard coding it into the Bloodhound initialisation (e.g. I don't want to use url: 'api/activity/&range=1,3')
I have the following valid JSON that I access remotely:
{
"meta": [
{
"name": "activity_id",
"table": "table",
"max_length": 4
},
{
"name": "activity_title",
"table": "table",
"max_length": 91
},
{
"name": "activity_level",
"table": "table",
"max_length": 2
}
],
"detail": [
{
"activity_id": "57",
"activity_title": "Help old ladies to cross the road.",
"activity_level": "2"
},
{
"activity_id": "58",
"activity_title": "Help mum with the washing up.",
"activity_level": "3"
},
{
"activity_id": "59",
"activity_title": "Shine my shoes",
"activity_level": "1"
},
{
"activity_id": "60",
"activity_title": "Put the bins out",
"activity_level": "1"
}
]
}
I set up a Bloodhound instance like this:
var activities = new Bloodhound({
datumTokenizer: function (datum) {
return Bloodhound.tokenizers.whitespace(datum.activity_title);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: '/api/activity/',
filter: function(data) {
return $.map(data['detail'], function(detail) {
return {
activity_id: detail.activity_id,
activity_title: detail.activity_title,
objective_level: detail.objective_level
};
});
}
}
});
I use Typeahead.js to do a lookup on the data as I type.
$( document ).on( "focus", ".typeahead-init", function() {
// + '&range=' + minimum + ',' + maximum
var minimum = $('#group-level-min-1').val();
var maximum = $('#group-level-max-1').val();
$(this).typeahead({
highlight: true
},
{
name: 'activity_title',
displayKey: 'activity',
source: activities.ttAdapter(),
templates: {
header: '<div class="header-name">Activities</div>',
empty: [
'<div class="empty-message">',
'No activities match your search',
'</div>'
].join('\n'),
suggestion: Handlebars.compile('<div class="typeahead-activity" id="typeahead-activity-{{activity_id}}"><strong>{{objective_level}}</strong> - {{activity_title}}</div>')
}
})
//info on binding selection at https://github.com/twitter/typeahead.js/issues/300
.bind('typeahead:selected', function(obj, datum, name) {
var target = $(this).closest('.activity-container');
var activityId = datum['activity_id'];
var url = '/api/activity/id/'+activityId;
$(target).children('.activity-id').val(activityId);
//http://runnable.com/UllA9u8MD5wiAACj/how-to-combine-json-with-handlebars-js-for-javascript-ajax-and-jquery
var raw_template = $('#activity-output').html();
// Compile that into an handlebars template
var template = Handlebars.compile(raw_template);
// Fetch all data from server in JSON
$.get(url,function(data,status,xhr){
$.each(data,function(index,element){
// Generate the HTML for each post
var html = template(element);
// Render the posts into the page
target.append(html);
});
});
});
$(this).removeClass("typeahead-init");
$(this).focus();
});
This has been cobbled together from several answers on Stackoverflow and others. Any help greatly appreciated.
I am building a web app where I need to display a tree using lists. My basic structure looks like this:
* Node 1
* Node 1.1
* Node 1.1.1
* Node 1.1.1.1
* Node 1.1.2
* Node 1.2
http://jsfiddle.net/QffFm/1/
I'm trying to find something in angular or bootstrap that I can use such that:
At first view of the list, it is expanded up to the third layer. In my fiddle, I would want to see Node 1, Node 1.1, Node 1.1.1, Node 1.1.2 and Node 1.2 (all but the 4th layer - Node 1.1.1.1)
On clicking on the list-style icon (not the word name of the node) The node collapses or expands
Ideally, I would love for the icon to change also dependent on if the item is expanded. A right arrow if there is more underneath, a down arrow if it is already expanded, and maybe a regular list item if there are no children
I am very new to AngularJS and still quite new to Bootstrap as well. I see that Angular has an accordion function which doesn't seem to quite handle everything I need it to.
I would love some direction on the best approach before I code a lot of logic into my web app that handles the different cases. I think this must be a common problem so perhaps there is something ready made that I can utilize. Any guidance would be much appreciated.
HTML code:
<div ng-app="myApp" ng-controller="controller">
<my-directive></my-directive>
<table style="width: 100%"><tbody><td>
<tree items="tree"></tree>
</td></tbody></table>
</div>
Angular code:
var app = angular.module('myApp', []);
app.controller('controller', function ($scope){
$scope.tree=[{"name":"Node 1","items":[{"name":"Node 1.1","items":[{"name":"Node 1.1.1","items":[{"name":"Node 1.1.1.1","items":[]}]},{"name":"Node 1.1.2","items":[]}]},{"name":"Node 1.2","items":[]}]}];
});
app.directive('tree', function() {
return {
template: '<ul><tree-node ng-repeat="item in items"></tree-node></ul>',
restrict: 'E',
replace: true,
scope: {
items: '=items',
}
};
});
app.directive('treeNode', function($compile) {
return {
restrict: 'E',
template: '<li >{{item.name}}</li>',
link: function(scope, elm, attrs) {
if (scope.item.items.length > 0) {
var children = $compile('<tree items="item.items"></tree>')(scope);
elm.append(children);
}
}
};
});
In followed example I used:
bootstrap
AngularJS recursive ng-include or (see second example) recursive directives
jQuery (will try to avoid in the future)
Demo 1 (ng-include) Plunker
From this model:
$scope.displayTree =
[{
"name": "Root",
"type_name": "Node",
"show": true,
"nodes": [{
"name": "Loose",
"group_name": "Node-1",
"show": true,
"nodes": [{
"name": "Node-1-1",
"device_name": "Node-1-1",
"show": true,
"nodes": []
}, {
"name": "Node-1-2",
"device_name": "Node-1-2",
"show": true,
"nodes": []
}, {
"name": "Node-1-3",
"device_name": "Node-1-3",
"show": true,
"nodes": []
}]
}, {
"name": "God",
"group_name": "Node-2",
"show": true,
"nodes": [{
"name": "Vadar",
"device_name": "Node-2-1",
"show": true,
"nodes": []
}]
}, {
"name": "Borg",
"group_name": "Node-3",
"show": true,
"nodes": []
}, {
"name": "Fess",
"group_name": "Node-4",
"show": true,
"nodes": []
}]
}];
[{
"name": "Android",
"type_name": "Android",
"icon": "icon-android icon-3",
"show": true,
"nodes": []
}];
}
The 2nd example is based on 2 directives:
app.directive('nodeTree', function() {
return {
template: '<node ng-repeat="node in tree"></node>',
replace: true,
transclude: true,
restrict: 'E',
scope: {
tree: '=ngModel'
}
};
});
app.directive('node', function($compile) {
return {
restrict: 'E',
replace:true,
templateUrl: 'the-tree.html',
link: function(scope, elm, attrs) {
// ....
if (scope.node.children.length > 0) {
var childNode = $compile('<ul ><node-tree ng-model="node.children"></node-tree></ul>')(scope)
elm.append(childNode);
}
}
};
});
(Added some checkboxes as well :))
Demo 2 Plunker
How it looks: