Related
Im using KendoUi grids everywhere now and need some help ..
When my Kendo grid first loads I want the user to have the rows and an empty row at the BOTTOM not the top to indicate that they can add data . I dont want to use the in built "Add Row Button".
I have the following
Try1
$(document).ready(function ()
{
var grid = $("#grid").data("kendoGrid");
grid.addRow();
$(".k-grid-edit-row").appendTo("#grid tbody");
}
This is supposed to move the row to the bottom of the grid , but it doesnt, it remans on top ?
Try 2
I also tried to do something like
var newRow = { field: "FirstName", Value: "" };
var grid = $("#grid").data("kendoGrid");
grid.dataSource.add(newRow);
This did not work either.
Try 3
But with this try , im not sure if there is a 'load' with the Kendoui Grid, i know there is a keydown , etc
grid.tbody.on('load', function (e)
{
if ($(e.target).closest('tr').is(':last-child'))
{
setTimeout(function ()
{
var totalrows = grid.dataSource.total();
var data = grid.dataSource.data();
var lastItem = data[data.length - 1];
if (typeof lastItem !== 'undefined')
{
if (lastItem.FirstName.trim() != "")
grid.addRow();
}
})
}
}
any help would be great.
The full implementation details is below:
First i add the datasource, this is a simple implementation.
var data = $scope.userdetails;
var dataSource = new kendo.data.DataSource({
transport: {
read: function (e) {
e.success(data);
},
update: function (e) {
e.success();
},
create: function (e) {
var item = e.data;
item.Id = data.length + 1;
e.success(item);
}
},
schema: {
model: {
id: "Id",
fields: {
FirstName: { type: "string" }
}
}
}
});
Then i define the grid
let grid = $("#grid").kendoGrid({
dataSource: dataSource,
scrollable: false,
navigatable: true,
editable: {
createAt: "bottom"
},
dataBound: function (e) {
e.sender.tbody.find(".k-grid-Delete").each(function (idx,
element) {
$(element).removeClass("k-button");
});
},
columns: [
{
field: "FirstName", title: "First Name"
},
{
command: [{ name: "Delete", text: "", click: $scope.delete,
className: "far fa-trash-alt fa-fw" }],
title: " ",
width: "100px",
attributes: { class: "k-grid-column-text-centre" }
}
]
}).data("kendoGrid");
I do the below process to add a blank row only when the user clicks tab on the last cell of the last row, but also want to add a blank when the page first loads with the grid.
grid.tbody.on('keydown', function (e) {
i`enter code here`f (e.keyCode == 9) {
if ($(e.target).closest('tr').is(':last-child')) {
setTimeout(function () {
var totalrows = grid.dataSource.total();
var data = grid.dataSource.data();
var lastItem = data[data.length - 1];
if (typeof lastItem !== 'undefined') {
if (lastItem.FirstName.trim() == "")
return;
}
grid.addRow();
})
}
}
});
This code still adds the row at the top of the grid not the bottom.
$(document).ready(function () {
var newRow = { field: "FirstName", Value: "" };
grid.dataSource.add(newRow);
grid.editRow($("#grid tr").last());
}
There is no other place that i add a row
You try #2 is the right way to go. It probably added a row at the bottom, right? So you just need to programatically edit it:
var newRow = { field: "FirstName", Value: "" };
var grid = $("#grid").data("kendoGrid");
grid.dataSource.add(newRow);
grid.editRow($("#grid tr").last());
Demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Kendo UI Snippet</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2020.2.513/styles/kendo.default-v2.min.css"/>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2020.2.513/js/kendo.all.min.js"></script>
</head>
<body>
<div id="grid"></div>
<script>
let grid = $("#grid").kendoGrid({
toolbar: ["save"],
columns: [
{ field: "name" },
{ field: "age" }
],
dataSource: {
data: [
{ id: 1, name: "Jane Doe", age: 30 },
{ id: 2, name: "John Doe", age: 33 }
],
schema:{
model: {
id: "id",
fields: {
age: { type: "number"}
}
}
}
},
editable: true
}).data('kendoGrid');
grid.dataSource.add({});
grid.editRow($("#grid tr").last());
</script>
</body>
</html>
Dojo
If someone is using the built-in method, just use editable.createAt parameter.
Here is a fiddle that shows the problem: http://jsfiddle.net/LkqTU/32602/
If you go to the fiddle you will notice the last column is a link. If you click the checkbox on the first column you lose the link. I would like to keep the link.
I am creating the link in the DataTable like so...
{
data: 'dept',
"fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
$(nTd).html("<a href='Freight_ITN.aspx?scn=" + oData.dept + "' target='_blank'>" + "ITN ENTRY" + "</a>");
}
The onClick event of the checkbox is where I am losing my link (I think):
$('#mytable tbody').on('click', 'input[type="checkbox"]', function (e) {
var active = $(this).prop('checked');
var $row = $(this).closest('tr');
console.log($row);
var record = oTable.row($row).data();
record.active = active;
//console.log(record);
oTable.row($row).data(record).draw(false);
});
I noticed that DataTable has a fnDrawCallback, however it appears to be deprecated, and I'm unsure how to use it to get my link back.
You need add the rendering function to the column definitions configuration for your DataTable.
See the following example: http://jsfiddle.net/34ufp3ps/1/
columnDefs: [{
render: function(value, type, record, cellIndex) {
if (record.active) {
return value; // If selected, show the value instead of a link.
} else {
return '' + 'ITN ENTRY';
}
},
targets: 4 // Column #4 (Dept)
}]
Code
I made your class names Capitalized and added a convenience insert() method for proper OOP encapsulation of your Model object.
function Employee(id, firstName, lastName, dept, active, displayAsLink) {
var self = this;
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.dept = dept;
this.active = active;
this.displayAsLink = displayAsLink;
}
function EmployeeModel() {
var self = this;
this.employees = [];
}
EmployeeModel.prototype.insert = function(employee) {
this.employees.push(employee);
}
var myModel = new EmployeeModel();
$(document).ready(function() {
myModel.insert(new Employee('1', 'Clara', 'Dellinger', 'IT', false, true));
myModel.insert(new Employee('2', 'John', 'Smith', 'HR', false, true));
myModel.insert(new Employee('3', 'Fred', 'Jones', 'Finance', false, false));
myModel.insert(new Employee('4', 'Mary', 'Jans', 'Finance', false, false));
myModel.insert(new Employee('5', 'Bob', 'Jones', 'IT', false, false));
myModel.insert(new Employee('6', 'Fred', 'Thebes', 'HR', false, true));
myModel.insert(new Employee('7', 'Sally', 'Jane', 'HR', false, true));
myModel.insert(new Employee('8', 'Patrick', 'Roberts', 'HR', false, true));
myModel.insert(new Employee('9', 'Lisa', 'Myers', 'Lab', false, true));
myModel.insert(new Employee('10', 'Roscoe', 'Coletrain', 'Security', false, true));
var table = $('#mytable').DataTable({
data: myModel.employees,
columns: [{
data: 'active',
render: function(data, type, row) {
if (type === 'display') {
return '<input type="checkbox" class="editor-active">';
}
return data;
},
className: "dt-body-center"
}, {
data: 'id'
}, {
data: 'firstName'
}, {
data: 'lastName'
}, {
data: 'dept'
}],
columnDefs: [{
render: function(value, type, record, cellIndex) {
if (record.active) {
return value;
} else {
return '' + 'ITN ENTRY';
}
},
targets: 4 // Column #4 (Dept)
}],
rowCallback: function(row, data) {
// Set the checked state of the checkbox in the table
$('input.editor-active', row).prop('checked', data.active);
},
aaSorting: [
[3, 'asc']
],
});
$('#mytable tbody').on('click', 'input[type="checkbox"]', function(e) {
var active = $(this).prop('checked');
var $row = $(this).closest('tr');
var employee = table.row($row).data();
employee.active = active;
//console.log(employee);
table.row($row).data(employee).draw(false);
});
$.fn.dataTable.ext.search.push(
function(oSettings, aData, iDataIndex) {
var isSelected = aData[0];
var keywords = $("#mysearch").val().toLowerCase().split(' ');
var matches = 0;
for (var k = 0; k < keywords.length; k++) {
var keyword = keywords[k];
for (var col = 0; col < aData.length; col++) {
if (aData[col].toLowerCase().indexOf(keyword) > -1) {
matches++;
break;
}
}
}
return (matches == keywords.length) || (isSelected === 'true')
}
);
$('#mysearch').keyup(function() {
table.draw();
});
});
.dataTables_filter {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jasny-bootstrap/3.1.3/js/jasny-bootstrap.min.js"></script>
<script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css" rel="stylesheet" />
<link href="http://cdnjs.cloudflare.com/ajax/libs/jasny-bootstrap/3.1.3/css/jasny-bootstrap.min.css" rel="stylesheet" />
<div>
<input type="text" id="mysearch" name="mysearch" placeholder="search" />
</div>
<table class="table" id="mytable">
<thead>
<tr>
<th>Select</th>
<th>Id</th>
<th>First</th>
<th>Last</th>
<th>Dept</th>
</tr>
</thead>
<tbody></tbody>
</table>
I just commented:
//table.row($row).data(employee).draw(true);
It is not necesssary to draw again in order to have the updated data.
employee.active = active;//this line updates the data.
You can add these two lines to verify:
e = table.row($row).data();
console.log(e);
The rendering function to the column definitions configuration for your DataTable is also correct.
I am trying to change the background color of selected row(s) in jquery datatable using my own css class but, the tick mark in the checkbox is not appearing.
If I remove className: 'selected-row' from the below code, then everything works normal but, without the color I want.
Fiddler: https://jsfiddle.net/8f63kmeo/12/
HTML:
<table id="CustomFilterOnTop" class="table table-bordered table-condensed" width="100%"></table>
JS
var Report4Component = (function () {
function Report4Component() {
//contorls
this.customFilterOnTopControl = "CustomFilterOnTop"; //table id
//data table object
this.customFilterOnTopGrid = null;
//variables
this.result = null;
}
Report4Component.prototype.ShowGrid = function () {
var instance = this;
//create the datatable object
instance.customFilterOnTopGrid = $('#' + instance.customFilterOnTopControl).DataTable({
columns: [
{ title: "<input name='SelectOrDeselect' value='1' id='ChkBoxSelectAllOrDeselect' type='checkbox'/>" },
{ data: "Description", title: "Desc" },
{ data: "Status", title: "Status" },
{ data: "Count", title: "Count" }
],
"paging": true,
scrollCollapse: true,
"scrollX": true,
scrollY: "300px",
deferRender: true,
scroller: true,
dom: '<"top"Bf<"clear">>rt <"bottom"<"Notes">i<"clear">>',
buttons: [
{
text: 'Load All',
action: function (e, dt, node, config) {
instance.ShowData(10000);
}
}
],
columnDefs: [{
orderable: false,
className: 'select-checkbox text-center',
targets: 0,
render: function (data, type, row) {
return '';
}
}],
select: {
style: 'multi',
selector: 'td:first-child',
className: 'selected-row'
}
});
};
Report4Component.prototype.ShowData = function (limit) {
if (limit === void 0) { limit = 100; }
var instance = this;
instance.customFilterOnTopGrid.clear(); //latest api function
instance.result = instance.GetData(limit);
instance.customFilterOnTopGrid.rows.add(instance.result.RecordList);
instance.customFilterOnTopGrid.draw();
};
Report4Component.prototype.GetData = function (limit) {
//structure of the response from controller method
var resultObj = {};
resultObj.Total = 0;
resultObj.RecordList = [];
for (var i = 1; i <= limit; i++) {
resultObj.Total += i;
var record = {};
record.Description = "This is a test description of record " + i;
record.Status = ["A", "B", "C", "D"][Math.floor(Math.random() * 4)] + 'name text ' + i;
record.Count = i;
resultObj.RecordList.push(record);
}
return resultObj;
};
return Report4Component;
}());
$(function () {
var report4Component = new Report4Component();
report4Component.ShowGrid();
report4Component.ShowData();
});
function StopPropagation(evt) {
if (evt.stopPropagation !== undefined) {
evt.stopPropagation();
}
else {
evt.cancelBubble = true;
}
}
Issue:
Any suggestion / help will be greatly appreciated.
It's the class selected that sets the checkbox tick etc. and by using a different class the selected class is no longer added.
You can just add both those classes instead, and it should work
select: {
style: 'multi',
selector: 'td:first-child',
className: 'selected-row selected'
}
FIDDLE
I am trying to learn JavaScript and I came across a practice problem in a book I purchased that I cannot seem to crack. The task is to flesh out a javascript formBuilder function to generate HTML forms dynamically from a JavaScript array. I have copied the code from the book onto a CodePen page for visual and testing purposes.
CodePen: http://codepen.io/anon/pen/gpwZMX
HTML sample:
<div>
<button data-sample='1'>Run 1</button>
<button data-sample='2'>Run 2</button>
<button data-sample='3'>Run 3</button>
</div>
<hr>
<div id='spec'>
<i>This div will display the currently-processed spec</i>
</div>
<br>Output:
<div id='result'>
<i>I sure wish I had a cool html form in me...</i>
</div>
<!--here are some test cases in docblock form-->
<div class='testcase' id='1'>
/** Comment Form
* Make a comment on the blog post!
* #param string[100] title
* #param email email
* #param text body
* #param bool subscribe Email me when someone comments on my comment!
*/
</div>
JavaScript sample:
var samples = [
{
title:"Comment Form",
desc:"Make a comment on the blog post!",
params:[
{
type: 'text',
max_length: 100,
name: 'title'
},
{
type: 'email',
name: 'email'
},
{
type:'textarea',
name:'body'
},
{
type:'checkbox',
name:'subscribe',
label:'mail me when someone comments on my comment!'
}
]
}]
formBuilder sample:
//builds an HTML form using all information present in `spec` and places the resulting HTML in jquery element `$el`
function formBuilder(spec,$el){
$el.html("<i>I still wish I had a cool html form in me...</i>");
}
$("button").on("click",function($e){
var specIndex = $($e.target).data('sample');
var specData = samples[specIndex-1];
$("#spec").html("Sample spec "+(specIndex)+" looks like: <br>"+JSON.stringify(specData));
formBuilder(specData, $("#result"));
});
Errors in the codepen code exist, paste the code below into your project:
var samples = [
{
title:"Comment Form",
desc:"Make a comment on the blog post!",
params:[
{
type: 'text',
max_length: 100,
name: 'title'
},
{
type: 'email',
name: 'email'
},
{
type:'textarea',
name:'body'
},
{
type:'checkbox',
name:'subscribe',
label:'mail me when someone comments on my comment!'
}
]
},
{
title:"Car Order Form",
desc:"Choose your car!",
params:[
{
type:'select',
values:['red','blue','green','black','white','taupe'],
name: 'color'
},
{
type: 'checkbox',
values:['fog-lights','radio','a-c','wheels','headlights'],
name: 'options'
},
{
type:'string',
minLength:7,
maxLength:7,
name:'vanityPlate',
optional:true
},
{
type:'int',
name:'price',
}
]
},
{
title:"New User Creator",
desc:"Create a new user account",
params:[
{
type:'string',
maxLength:20,
name:'fname',
label:'First Name'
},
{
type:'string',
maxLength:20,
name:'lname',
label:'Last Name'
},
{
type:'date',
name:'dob',
label:'Date of Birth'
},
{
type:'email',
multiple:true,
maxCount:4,
name:'emails',
label:'Email Addresses'
},
{
type: 'string',
name: 'addr1',
label: 'Street Address'
},
{
type: 'string',
name: 'city'
},
{
type: 'state',
name: 'state',
},
{
type: 'int',
name: 'zipcode',
maxValue: 99999,
minValue: 0,
label: 'ZIP'
},
]
}
]
//builds an HTML form using all information present in `spec` and places the resulting HTML in jquery element `$el`
function formBuilder(spec,$el){
var inputs = getInputs(spec);
$el.html("<form title='"+spec.title+"'><fieldset><legend>"+spec.desc+"</legend>"+inputs+"</fieldset></form>");
}
function getInputs(spec) {
var inputs = "";
for(var i = 0; i < spec.params.length; i++) {
var input = "<input ";
var attributes = JSON.stringify(spec.params[i]).split(",");
console.log(attributes);
for(var j = 0; j < attributes.length; j++) {
$.each(spec.params[i], function(key, value) {
input += key + "='" + value + "' ";
});
}
inputs += input + "/><br/>";
}
return inputs;
}
$("button").on("click",function($e){
var specIndex = $($e.target).data('sample');
var specData = samples[specIndex-1];
$("#spec").html("Sample spec "+(specIndex)+" looks like: <br>"+JSON.stringify(specData));
formBuilder(specData, $("#result"));
});
The last item in an array does not get a comma appended to it. Always ensure to end a line of code with a semi-colon as well. Those are the changes I made to your code, now it runs, as I assume, correctly unless you have any other issues?
I found some code on GitHub (https://github.com/RallyCommunity/TagCloud) for displaying a TagCloud in Rally. Conceptually it looks great but I cannot seem to get it to work and wondered if there were any Rally JavaScript experts out there who could take a quick look.
I modified it slightly as the URL for the Analytics was incorrect (according to the docs) and the API's were hard coded to depreciated versions so I updated those.
I'm not a JavaScript expert. When I run this it doesn't find any Tags against stories.
When I run this in Chrome debugging mode I can take the URL and execute it in my browser but it also does not come back with any Tags. It comes back with a full result response from Analytics, but has no tags and I know there are tags against stories in the selected project.
Any ideas from anyone?
<!DOCTYPE html>
<html>
<head>
<title>TagCloud</title>
<script type="text/javascript" src="/apps/2.0p/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
layout: 'border',
items: [
{
title: 'Tag Cloud',
xtype: 'panel',
itemId: 'cloud',
region: 'west',
width: '30%',
collapsible: true,
bodyStyle: 'padding:15px',
listeners: { 'afterRender': function(el) { setTimeout(function() { el.setLoading(); }, 500);}} // needs a little delay
},
{
title: '<<< Select a tag from the Tag Cloud',
xtype: 'panel',
itemId: 'grid',
region: 'center',
width: '70%',
collapsible: false
}
],
tagMap : [],
maxFont : 24, // largest desired font size
minFont : 8, // and smallest
_renderTag : function renderHandler(tagLabel) {
tagLabel.getEl().on('click',this._tagSelected, this);
},
// does the actual building of the cloud from 'tagMap'
_buildCloud: function(app, response) {
//title: '<<< Select a tag from the Tag Cloud - Building',
var i, tag;
for (i=0;i<response.Results.length;i++) {
tag = response.Results[i];
if(typeof app.tagMap[tag.ObjectID] !== "undefined") {
app.tagMap[tag.ObjectID].Name = tag._refObjectName;
}
}
if(response.StartIndex+response.PageSize < response.TotalResultCount) {
app._queryForTagNames(response.StartIndex+response.PageSize, app, app._buildCloud);
} else {
if(app.tagMap.length === 0) {
tag = new Ext.form.Label({
id: 'tagNone',
text: ' No tagged Stories found '
});
app.down('#cloud').add(tag);
} else {
var minFrequency = Number.MAX_VALUE;
var maxFrequency = Number.MIN_VALUE;
var tuples = [];
for (var x in app.tagMap) {
if (app.tagMap.hasOwnProperty(x)) {
tuples.push([x, app.tagMap[x]]);
if(app.tagMap[x].count > maxFrequency) {
maxFrequency = app.tagMap[x].count;
}
if(app.tagMap[x].count < minFrequency) {
minFrequency = app.tagMap[x].count;
}
}
}
tuples.sort(function(a,b) { a = a[1]; b = b[1]; return a.Name > b.Name ? 1 : a.Name < b.Name ? -1 : 0 ;});
for (i = 0; i < tuples.length; i++) {
var ftsize = ((tuples[i][1].count-minFrequency)*(app.maxFont-app.minFont) / (maxFrequency-minFrequency)) + app.minFont;
tag = new Ext.form.Label({
id: 'tag'+tuples[i][0],
text: ' ' + tuples[i][1].Name + ' ',
overCls: 'link',
style:"font-size: "+ftsize+"pt;",
listeners: { scope: app, render: app._renderTag }
});
app.down('#cloud').add(tag);
}
}
app.getComponent('cloud').setLoading(false);
}
},
// collects the _queryForTags responses and calls _queryForTagNames when it has them all
_buildTagMap: function(app, response) {
for (var i=0;i<response.Results.length;i++) {
var ent = response.Results[i];
for (var j=0; j < ent.Tags.length; j++) {
var tag = ent.Tags[j];
var mapent = app.tagMap[tag];
if(typeof mapent === "undefined") {
mapent = { count: 1 };
} else {
mapent.count++;
}
app.tagMap[tag] = mapent;
}
}
if(response.StartIndex+response.PageSize < response.TotalResultCount) {
app._queryForTags(response.StartIndex+response.PageSize, app, app._buildTagMap);
} else {
app._queryForTagNames(0, app, app._buildCloud);
}
},
// get a list of the tags from the Lookback API, iterating if necessary (see _buildTagMap)
_queryForTags: function(start, app, callback) {
var params = {
find: "{'Tags':{'$exists':true}, '__At':'current', '_Type':'HierarchicalRequirement', '_ProjectHierarchy':"+ this.getContext().getProject().ObjectID +" }",
fields: "['Tags']",
pagesize: 20000,
start: start
};
Ext.Ajax.request({
url: 'https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/'+ this.context.getWorkspace().ObjectID + '/artifact/snapshot/query.js',
method: 'GET',
params: params,
withCredentials: true,
success: function(response){
var text = response.responseText;
var json = Ext.JSON.decode(text);
callback(app, json);
}
});
},
// once all the tags have been collected, get a list of the tag names from the WSAPI, iterating if necessary (see _buildCloud)
_queryForTagNames: function(start, app, callback) {
Ext.Ajax.request({
url: 'https://rally1.rallydev.com/slm/webservice/1.41/tag.js',
method: 'GET',
params: { fetch: "ObjectID", pagesize: 200, "start": start},
withCredentials: true,
success: function(response){
callback(app, Ext.JSON.decode(response.responseText).QueryResult);
}
});
},
_queryForStories: function(tagOid) {
Ext.create('Rally.data.WsapiDataStore', {
model: 'UserStory',
autoLoad: true,
fetch: ['Rank', 'FormattedID', 'Name', 'ScheduleState'],
filters: [{
property:'Tags',
operator: '=',
value: "tag/" + tagOid
}],
sorters: [{
property: 'Rank',
direction: 'ASC'
}],
listeners: {
load: this._onDataLoaded,
scope: this
}
});
},
_tagSelected: function(app, elem) {
this.getComponent('grid').setLoading();
this._queryForStories(elem.id.substring(3)); // cheesy, id is "tag"+tagOid, we need the oid
this.tagName = elem.innerText;
},
_onDataLoaded: function(store, data) {
var records = [], rankIndex = 1;
Ext.Array.each(data, function(record) {
records.push({
Ranking: rankIndex,
FormattedID: record.get('FormattedID'),
Name: record.get('Name'),
State: record.get('ScheduleState')
});
rankIndex++;
});
var customStore = Ext.create('Rally.data.custom.Store', {
data: records,
pageSize: 25
});
if(!this.grid) {
this.grid = this.down('#grid').add({
xtype: 'rallygrid',
store: customStore,
columnCfgs: [
{ text: 'Ranking', dataIndex: 'Ranking' },
{ text: 'ID', dataIndex: 'FormattedID' },
{ text: 'Name', dataIndex: 'Name', flex: 1 },
{ text: 'State', dataIndex: 'State' }
]
});
} else {
this.grid.reconfigure(customStore);
}
this.getComponent('grid').setTitle('Stories tagged: ' + this.tagName);
this.getComponent('grid').setLoading(false);
},
launch: function() {
this._queryForTags(0, this, this._buildTagMap);
}
});
Rally.launchApp('CustomApp', {
name: 'TagCloud'
});
});
</script>
<style type="text/css">
.app {
}
.link {
color: #066792;
cursor: pointer;
} </style>
</head>
<body></body>
</html>
The code was out-of-date with respect to the most-recent LBAPI changes - specifically the use of _Type vs _TypeHierarchy and of course, the url, as you'd already discovered. Please pick up the changes and give it a whirl.