Error with list.js sortable table - javascript

When using list.js and tabletop for a sortable table taken from a Gdoc, I get the error: "Uncaught TypeError: Cannot read property 'childNodes' of undefined" on the first line of list.js.
Because the website I work for can only have JS uploaded, I need to write all my html using js or jquery, so it's a bit wonky. I think the error is being thrown because of the order I have everything, but I have tried moving things around to no avail. Everything is working other than the sorting.
Thanks!
HTML file
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
<script type="text/javascript" src="list.js-master/dist/list.min.js"></script>
<script type="text/javascript" src="src/tabletop.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div id="tablesetter"></div>
</body>
<script type="text/javascript">
var url = 'url to gdoc here';
$(document).ready( function(){
Tabletop.init( {key: url, callback: showInfo, parseNumbers: true} )})
function showInfo(data, tabletop){
$("#tablesetter").append('<h2>Table Working</h2><table><thead><th class="sort" data-sort="university">University</th><th class="sort" data-sort="no">Billionaires</th><th class="sort" data-sort="no2">Billionaires Rank</th><th class="sort" data-sort="rank">U.S. News Rank</th></thead><tbody class="list"></tbody></table>');
$.each(tabletop.sheets("Sheet1").all(), function(i, cat){
var htmltable = $('<tr><td class="university">' + cat.university + '</td>');
htmltable.append('<td class="no">' + cat.numberofbillionaires + '</td>');
htmltable.append('<td class="no2">' + cat.rankedbybillionaires + '</td>');
htmltable.append('<td class="rank">' + cat.usnewsranking + '</td></tr>');
htmltable.appendTo("tbody");
})
}
</script>
<script type="text/javascript" src="options.js"></script>
</html>
JS file
var options = {
valueNames: [ 'university', 'no' , 'no2' , 'rank']
};
var userList = new List('tablesetter', options);

The problem
var userList = new List('tablesetter', options); should be executed when the dom has an element of the list class; since in the question's code the list class default to list" , so such element should be <tbody class="list"> that is going to be appended to the #tablesetter only when the showInfo function receive data from google.
The solution
We ensure that the var userList = new List('tablesetter', options) statement executes after ( ie: at the end ) of the showInfo function; in other words move var userList = new List('tablesetter', options); from options.js just before the closing right bracket of the showinfo function.
More details
in the question's code when list.js tries to init() the dom is:
and list.list is still undefined when list.js defines it's getItemSource() functions:
with the proposed fix, at the var userList = new List('tablesetter', options); the dom is like:
and when defines it's getItemSource() functions the list.list can use the tbody as aspected:

If you look at this post, I'm sure your just missing some of the minimum requirements for list.js to function properly. Try to dynamically add the input with id and class of "search" as well with your other classes. Let me know if this helps.
https://stackoverflow.com/a/23078200/4812515

Related

Get data from Materialize CSS chips

I need to get data from Materialize CSS chips, but I don't know, how.
$('.chips-placeholder').material_chip({
placeholder: 'Stanici přidíte stisknutím klávesy enter',
secondaryPlaceholder: '+Přidat',
});
function Show(){
var data = $('.chips-placeholder').material_chip('data');
document.write(data);
}
<!-- Added external styles and scripts -->
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css">
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- HTML body -->
<div class="chips chips-placeholder"></div>
<button onclick="Show()" type="button">Show</button>
So, to access to the data's chip you just have to do this:
var data = $('#id of your chips div').material_chip('data');
alert(data[0].tag);`
'0' is the index of your data (0, 1, 2 , 3, ...).
'tag' is the chip content. You can also get the id of your data with '.id'.
To get data from Materialize CSS chips, use the below code.
$('#button').click(function(){
alert(JSON.stringify(M.Chips.getInstance($('.chips')).chipsData));
});
They appear to have changed the method available in the latest version.
The documentation suggests that you should be able to access the values as properties of the object, but I’ve spent an hour looking, not getting anywhere.
Until the following happened
$('.chips-placeholder').chips({
placeholder: 'Enter a tag',
secondaryPlaceholder: '+Tag',
onChipAdd: (event, chip) => {
console.log(event[0].M_Chips.chipsData);
},
During the onChipAdd event I was able to access the event. Within this object was an array of tags.
I know this isn't the documented way, however there is only so much time a client will accept when it comes billing and I must move on.
This worked great for me
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.chips');
var instances = M.Chips.init(elems, {
placeholder: "Ajouter des Tags",
secondaryPlaceholder: "+tag",
onChipAdd: chips2Input,
onChipDelete: chips2Input,
Limit: 10,
minLength: 1
});
function chips2Input(){
var instance = M.Chips.getInstance(document.getElementById('chip1')), inpt = document.getElementById('myInputField');
inpt.value = null;
for(var i=0; i<instance.chipsData.length; i++){
if(inpt.value == null)
inpt.value = instance.chipsData[i].tag;
else{
inpt.value += ','+instance.chipsData[i].tag; //csv
}
}
console.log('new value: ', inpt.value);
}
});
</script>

Why FooTable not callable?

I am working on a project where we are trying to implement a jQuery plugin called Footable. It works by calling the function .footable() on the table being selected by jQuery. When I tried to call this function I got a type error: undefined is not a function.
We are also using prototypejs in this project so at first I though that the problem was that footable was using $.() instead of jQuery.(), and it was. I went in and changed the $[.(] to jQuery hoping that it would fix the problem, but I am still unable to call .footable().
You should also know that I am loading footble.js from an Iframe. I'm not sure if that would cause any problems.
I'm not sure what to try next. Any advice is appreciated.
Thanks in advance
UPDATE 1
I have tried entering the following code in the console
var $j = jQuery.noConflict();
$j('<table></table>').footable();
In an environment that successfully loads footable an object is returned with the footable classes. In my enviornment I get a "TypeError: undefined is not a function".
make sure load jquery first, and then footable
and $ is alias from jQuery, so its should not a problem, u can use $() or jQuery()
based on your question, you should use $() or jQuery(), not $.() or jQuery.()
I think you're on the right track with there being a conflict.
Here's a plunk that demonstrates the issue: http://plnkr.co/edit/2sR7F2W0QGJAcXxgez14
In the plunk, if JQuery is still reference by $ and you add the reference to Prototype, you see that Footable stops working. If you use the JQuery NoConflict and then use that instead of $, Footable starts work as expected again.
Here's where I define the scripts:
<head>
<link data-require="bootstrap-css#3.0.2" data-semver="3.0.2" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css" />
<link data-require="jqueryui#*" data-semver="1.10.0" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/css/smoothness/jquery-ui-1.10.0.custom.min.css" />
<link rel="stylesheet" href="footable.core.css" />
<script data-require="jquery#*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script data-require="jqueryui#*" data-semver="1.10.0" src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/jquery-ui.js"></script>
<script data-require="bootstrap#*" data-semver="3.0.2" src="//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js"></script>
<script>var $j = jQuery.noConflict();</script>
<script src="footable.js"></script>
<script src="footable.filter.js"></script>
<script data-require="prototype#*" data-semver="1.7.1+0" src="//cdnjs.cloudflare.com/ajax/libs/prototype/1.7.1.0/prototype.js"></script>
</head>
Then when I use JQuery and Call footable():
$j(function() {
window.footable.options.filter.filterFunction = function(index) {
var $t = $j(this),
$table = $t.parents('table:first'),
filter = $table.data('current-filter').toUpperCase(),
columns = $t.find('td');
var regEx = new RegExp("\\b" + filter + "\\b");
var result = false;
for (i = 0; i < columns.length; i++) {
var text = $j(columns[i]).text();
result = regEx.test(text.toUpperCase());
if (result === true)
break;
if (!$table.data('filter-text-only')) {
text = $j(columns[i]).data("value");
if (text)
result = regEx.test(text.toString().toUpperCase());
}
if (result === true)
break;
}
return result;
};
$j('table').footable().bind('footable_filtering', function(e) {
var selected = $j('.filter-status').find(':selected').text();
if (selected && selected.length > 0) {
e.filter += (e.filter && e.filter.length > 0) ? ' ' + selected : selected;
e.clear = !e.filter;
}
});
}
If you want to continue to use $ jquery you could do something like: (jQuery and prototype.js conflict, how to keep jQuery as $?)
(function($) {
$('table').footable();
})(jQuery);

Automatic two way binding with Knockout

I'm just getting started with Knockout.js and i have a view(html) which is supposed to be populated by data from a rest api via jquery's $.getJSON method.
When i run the app, nothing shows but using firebug i can see that the 'GET' query returns a status code of 200 and the right data.
I'm at a fix as to why nothing shows in the view since the bindings in Knockout.js are supposed to be automatic.
Below is my code.
Thanks
<div id ='main'>
<!-- ko foreach: posts -->
<p>Hello</p><span data-bind="text: title"></span></p><p data-bind="text: content"></p>
<p data-bind="text: author"></p><p data-bind="text: date"></p>
<!-- /ko -->
</div>
</body>
<script type="text/javascript">
function Post(data){
this.title = ko.observable(data.title);
this.content = ko.observable(data.content);
this.author = ko.observable(data.author);
this.date = ko.observable(data.date)
}
function PostListViewModel(){
var self = this;
self.posts = ko.observableArray([]);
$.getJSON("/posts", function(getPost){
var mappedPost = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPost);
});
}
var postlistviewmodel = new PostListViewModel();
ko.applyBindings(postlistviewmodel);
</script>
This should be:
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPosts);
});
wouldn't do self.posts.push(mappedPosts[i]) at all. You should just pass mappedPosts through the ko binding in order to update the listeners.
If your just getting the latest posts and want to update your current list simply do:
var allPosts = self.posts().concat(mappedPosts);
self.posts(allPosts);
You don't need the model to have ko.observable if you're just displaying them. If you want to edit model as well, then leave as.
Also, I tend to do this for single or multiple view models:
ko.applyBindings({viewModel : new viewModel() };
This allows for having multiple named view models. Access scope using: $root.viewModel
This is what I did earlier: http://jsfiddle.net/jFb3X/
Check your code against this fiddle then.
Script tags also need to be above the closing body tags
<html>
<head>
</head>
<body>
<!-- all your html content -->
<script type="text/javascript">
var viewModel = function () {
}
ko.applyBindings({viewModel : new viewModel()});
</script>
</body>
</html>
Is it something as simple as waiting for the DOM to be ready?
Are you able to try the following:
$(function () {
ko.applyBindings(postlistviewmodel);
});
Source: I've done this a few times and been stumped for a bit trying to see what I did wrong. :-)
(As a style thing, I'd also move the /body to after the /script - probably not related to your issue though).
I suspect you get multiple posts from /posts. You only push a single item (array).
...
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
for(var i = 0; i < mappedPosts.length; i++) {
self.posts.push(mappedPosts[i]);
}
});
...

Uncaught TypeError: Cannot read property 'Constructor' of undefined

I am getting this and a couple other weird error messages on my main ASP MVC 3 layout page.
I am using the following scripts
<script src="#Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-1.8.3.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/typeahead.js")" type="text/javascript"></script>
And trying to get the typeahead.js to work in our nav bar. Below is the code I currently have on my machine. I had this working at one point in time, however after a sync up with a coworker the typeahead search does not work anymore and I haven't been able to track down the issue.
The first line in the code below gives the following error
Uncaught TypeError: Cannot read property 'Constructor' of undefined
If I comment out the protoype.blur function, however, I then get this error
Uncaught TypeError: Object [object Object] has no method 'typeahead'
Which points to the $('.AgentSearch .typeahead).typeahead function. Been stuck on this for hours, any help would be greatly appreciated. Thanks
// Workaround for bug in mouse item selection
$.fn.typeahead.Constructor.prototype.blur = function () {
var that = this;
setTimeout(function () { that.hide() }, 250);
};
$('.AgentSearch').typeahead({
source: function (term, process) {
var url = '#Url.Action("GetAgents", "Agent")';
var agents = [];
map = {};
return ($.getJSON(url, { term: term }, function (data) {
$.each(data, function (i, item) {
map[item.Name] = item;
agents.push(item.Name);
});
process(agents);
}));
},
highlighter: function (item) {
var p = map[item];
var display = ''
+ "<div class='typeahead_wrapper'>"
+ "<div class='typeahead_labels'>"
+ "<div class='typeahead_primary'>" + p.Name + "</div>"
+ "<div class='typeahead_third'><i>LastFour:</i> " + p.LastFour + "</div>"
+ "</div>"
+ "</div>";
return display;
},
updater: function (item) {
window.location.href = ("/Monet/Agent/Details/" + map[item].SymetraNumber);
}
});
Here is the search box I'm binding this to
<form class="navbar-search pull-left">
<input type="text" name="names" value="" id="AgentSearch" class="search-query" data-provide="typeahead" placeholder=" Agent Search"/>
</form>
EDIT
Here are the script tags as they're rendered by the browser
<script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery-1.8.3.js" type="text/javascript"></script>
<script src="/Scripts/jquery-ui.js" type="text/javascript"></script>
<script src="/Scripts/typeahead.js" type="text/javascript"></script>
It looks like typeahead is not defined.
If you're trying to extend typeahead, this article may help:
Extend the bootstrap-typeahead in order to take an object instead of a string
$.fn will always return an object ('[]'), this is why the error change when you comment-out .prototype.blur, but they're both indicating 'typeahead' doesn't exist.
Just a guess, but it could be a synchronicity issue where your code is running before the library loads.

"Cannot call method 'oEmbed' of null" when embedding Soundcloud player in dynamically generated Div

Using the Soundcloud JavaScript API, I want to dynamically generate a page of player widgets using track search results. My code is as follows:
<html>
<head>
<script src="http://connect.soundcloud.com/sdk.js"></script>
<script>
function makeDivsFromTracks(tracks,SC)
{
var track;
var permUrl;
var newDiv;
for(var ctr=0;ctr<tracks.length;ctr++)
{
newDiv=document.createElement("div");
newDiv.id="track"+ctr;
track=tracks[ctr];
SC.oEmbed(track.permalink_url,{color:"ff0066"},newDiv);
document.body.appendChild(newDiv);
}
}
</script>
</head>
<body>
<script>
SC.initialize({
client_id: 'MY_CLIENT_ID'
});
SC.get('/tracks',{duration:{to:900000},tags:'hitech',downloadable:true},
function(tracks,SC)
{
makeDivsFromTracks(tracks,SC);
});
</script>
</body>
</html>
When I load this, the SC.oEmbed() call throws an error:
Uncaught TypeError: Cannot call method 'oEmbed' of null
which would seem to indicate that either the divs aren't being generated or the search results aren't being returned, but if I remove the SC.oEmbed() call and replace it with:
newDiv.innerHTML=track.permalink_url;
then I get a nice list of the URLs for my search results.
And if I create a widget using a static div and static URL, e.g.
<body>
<div id="putTheWidgetHere"></div>
<script>
SC.initialize({
client_id: 'MY_CLIENT_ID'
});
SC.oEmbed("http://soundcloud.com/exampleTrack", {color: "ff0066"}, document.getElementById("putTheWidgetHere"));
</script>
</body>
then that works fine as well. So what's the problem with my oEmbed() call with these dynamically created elements?
Solved it. I took out the SC argument from the callback function and makeDivsFromTracks(), and now all the players show up. Not sure exactly why this works--maybe it has to do with the SC object being defined in the SDK script reference, so it's globally available and doesn't need to be passed into functions?
Anyways, working code is:
<html>
<head>
<script src="http://connect.soundcloud.com/sdk.js"></script>
<script>
function makeDivsFromTracks(tracks)
{
var track;
var permUrl;
var newDiv;
for(var ctr=0;ctr<tracks.length;ctr++)
{
newDiv=document.createElement("div");
newDiv.id="track"+ctr;
track=tracks[ctr];
//newDiv.innerHTML=track.permalink_url;
SC.oEmbed(track.permalink_url,{color:"ff0066"},newDiv);
document.body.appendChild(newDiv);
}
}
</script>
</head>
<body>
<script>
SC.initialize({
client_id: 'MY_CLIENT_ID'
});
SC.get('/tracks',{duration:{from:180000,to:900000},tags:'hitech',downloadable:true},function
(tracks){makeDivsFromTracks(tracks);});
</script>
</body>
</html>

Categories

Resources