Create HTML Table with HandleBars.js - ember.js

I need to create a table with HandleBars and json. my proposal is some thing like this :
<script type="text/x-handlebars">
{{NGRID 'json'}}
</script>
and register helper for NGRID is something like this :
Handlebars.registerHelper('NGRID',function(json){
// create elements <table> and a <tbody>
var tbl = document.createElement("table");
var tblBody = document.createElement("tbody");
// cells creation
for (var j = 0; j <= 2; j++) {
// table row creation
var row = document.createElement("tr");
for (var i = 0; i < 2; i++) {
// create element <td> and text node
//Make text node the contents of <td> element
// put <td> at end of the table row
var cell = document.createElement("td");
var cellText = document.createTextNode("cell is row "+j+", column "+i);
cell.appendChild(cellText);
row.appendChild(cell);
}
//row added to end of table body
tblBody.appendChild(row);
}
// append the <tbody> inside the <table>
tbl.appendChild(tblBody);
// put <table> in the <body>
// tbl border attribute to
tbl.setAttribute("border", "2");
return tbl;
});
but in my html file the result is something like this :
[object HTMLTableElement]
but i want to see table.

Handlebars use the toString from the returned object, because this you receive [object HTMLTableElement].
Also, handlebars escape the returned string, to prevent XSS attack. You need to use Handlebars.SafeString to your html don't be escaped, in the content that you trust.
For simplicity I return new Handlebars.SafeString(tbl.outerHTML) and work.
http://jsfiddle.net/Y2RWh/

Related

Django has no response to anchor tag

test
...
<div class="tab-pane " id="test">
<table>
...
</table>
</div>
When #test anchor is clicked, the behavior should be logged in the server. So in urls.py, I defined something like this
url(r'#test$', views.log())
or
url(r'.*#test$', views.log())
But it seems it doesn't work.
I have to use anchor here, because I don't want to refresh the page.
Any ideas?
Here is some JavaScript that takes links with a href attribute starting with # and makes a request to https://localhost:8000/<whatever was after the hash sign> whenever the links are clicked. It's not robust and it needs to be modified for your circumstances, but maybe it works as a starting point.
var hashLinks = document.querySelectorAll('a[href^="#"]');
var i;
function hashLinkClicked(event) {
var hash, url, request;
// You probably want to allow default link behaviour here
event.preventDefault();
hash = this.hash;
// Cut hash character out of URL
url = 'http:/localhost:8000/' + hash.slice(1);
request = new XMLHttpRequest();
request.onreadystatechange = function () { /* Handle response here */ };
request.open('GET', url);
request.send();
}
for (i = 0; i < hashLinks.length; i++) {
hashLinks[i].addEventListener('click', hashLinkClicked);
}

Rails or Ember object model breaking browser's pushState functionality?

** I'm using Ember.Object instead of Ember Data, to pull data from an api and I believe that might be causing the issue.**
I have my resources nested as so:
Mdm.Router.map ->
#resource "groups", ->
#resource "group", path: ':group_id'
'/groups/ loads a list of all groups on the left side of the browser. Each group is linking to its specific group_id. When clicked, the 'group' template renders on the right side of the screen, showing details of one group while the list remains to the left.
However, when you click the back button, or manually enter the group_id into the url the individual groups dont render. The url will update in the browser window, but the content wont change to match it.
I have the singular 'group' template rendering inside of the 'groups' template with the {{outlet}}.
My groups_route.js.coffee looks like this:
Mdm.GroupsRoute = Ember.Route.extend(model: ->
Mdm.Group.all()
)
application.hbs:
<div class="container">
<div class="nav-bar">
<img src="assets/logo_loginbox.png" class="logo">
<ul class="nav-menu">
<li>GROUPS</li>
<li>USERS</li>
</ul>
</div><!-- nav-bar -->
<hr>
{{outlet}}
</div><!-- container -->
groups.hbs:
<h1>Groups</h1>
{{ partial groupsList }}
<div class="group">
{{outlet}}
</div><!-- group -->
group.hbs:
<h1>{{name}}</h1>
I'm getting the following error in the console when I use the back button or try to load the page with the group_id present:
Uncaught TypeError: Object function () {
if (!wasApplied) {
Class.proto(); // prepare prototype...
}
o_defineProperty(this, GUID_KEY, undefinedDescriptor);
o_defineProperty(this, '_super', undefinedDescriptor);
var m = meta(this);
m.proto = this;
if (initMixins) {
// capture locally so we can clear the closed over variable
var mixins = initMixins;
initMixins = null;
this.reopen.apply(this, mixins);
}
if (initProperties) {
// capture locally so we can clear the closed over variable
var props = initProperties;
initProperties = null;
var concatenatedProperties = this.concatenatedProperties;
for (var i = 0, l = props.length; i < l; i++) {
var properties = props[i];
Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
for (var keyName in properties) {
if (!properties.hasOwnProperty(keyName)) { continue; }
var value = properties[keyName],
IS_BINDING = Ember.IS_BINDING;
if (IS_BINDING.test(keyName)) {
var bindings = m.bindings;
if (!bindings) {
bindings = m.bindings = {};
} else if (!m.hasOwnProperty('bindings')) {
bindings = m.bindings = o_create(m.bindings);
}
bindings[keyName] = value;
}
var desc = m.descs[keyName];
Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty));
Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
var baseValue = this[keyName];
if (baseValue) {
if ('function' === typeof baseValue.concat) {
value = baseValue.concat(value);
} else {
value = Ember.makeArray(baseValue).concat(value);
}
} else {
value = Ember.makeArray(value);
}
}
if (desc) {
desc.set(this, keyName, value);
} else {
if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
this.setUnknownProperty(keyName, value);
} else if (MANDATORY_SETTER) {
Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
} else {
this[keyName] = value;
}
}
}
}
}
finishPartial(this, m);
delete m.proto;
finishChains(this);
this.init.apply(this, arguments);
} has no method 'find' application.js:51233
Mdm.GroupRoute.Ember.Route.extend.model application.js:51233
superWrapper application.js:12849
Ember.Route.Ember.Object.extend.deserialize application.js:36503
collectObjects application.js:35614
proceed application.js:35638
(anonymous function) application.js:1193
fire application.js:1038
self.fireWith application.js:1149
(anonymous function) application.js:1200
fire application.js:1038
self.fireWith application.js:1149
done application.js:8075
script.onload.script.onreadystatechange

find divs with id

Hi I'm very new to regex and I need some help with writing this or at least getting me started.
I would like to get all the divs on the page and put them into a string collection
there might be spaces between the < and div and a spaces between the < / div > thanks
I have tried the htmlaggilitypack but was experiencing issues thats why I am going this way
Dim reg As Regex = New Regex("<div(.*?)> </div")
Dim matches As string() = reg.Matches(htmlCode)
<div id="out">
<div id="one">
< div id="b"></div>
< div id="d"></div>
</div>
<div id="two">
<h1>fsdfsdf</h1>
< div id="a"><div id="a"></div></div>
< / div >
</div>
If you want to return a collection of divs by an ID value then you could use the following with HMTL agility pack:
protected void Page_Load(object sender, EventArgs e)
{
List<HtmlAgilityPack.HtmlNode> divs = GetDivsInner();
foreach (var node in divs)
{
Response.Write("Result: " + node.InnerHtml.ToString());
}
}
public List<HtmlAgilityPack.HtmlNode> GetDivsInner()
{
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.OptionFixNestedTags = true;
doc.Load(requestData("YOUR URL HERE"));
var divList = doc.DocumentNode.Descendants("div").Where(d => d.Attributes.Contains("id") && d.Attributes["id"].Value.Contains("YOUR ID VALUE")).ToList();
return divList;
}
public StreamReader requestData(string url)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader sr = new StreamReader(resp.GetResponseStream());
return sr;
}
Try
<\s*div.*>(.|\n)*<\s*/\s*div>
as your regex pattern. Have tested it with the following and it matches all
<div id='d'>
dsfdsfs
dsfdfd
</div>
< div >dave </div>
<div>home </ div>
<p></p>
however if you want to tweak it there are some great tools on the internet to test your regular expressions
http://www.regextester.com/
http://derekslager.com/blog/posts/2007/09/a-better-dotnet-regular-expression-tester.ashx

CheckBoxList multiple selections: how to model bind back and get all selections?

This code:
Html.CheckBoxList(ViewData.TemplateInfo.HtmlFieldPrefix, myList)
Produces this mark-up:
<ul><li><input name="Header.h_dist_cd" type="checkbox" value="BD" />
<span>BD - Dist BD Name</span></li>
<li><input name="Header.h_dist_cd" type="checkbox" value="SS" />
<span>SS - Dist SS Name</span></li>
<li><input name="Header.h_dist_cd" type="checkbox" value="DS" />
<span>DS - Dist DS Name</span></li>
<li><input name="Header.h_dist_cd" type="checkbox" value="SW" />
<span>SW - Dist SW Name </span></li>
</ul>
You can check multiple selections. The return string parameter Header.h_dist_cd only contains the first value selected. What do I need to do to get the other checked values?
The post method parameter looks like this:
public ActionResult Edit(Header header)
I'm assuming that Html.CheckBoxList is your extension and that's markup that you generated.
Based on what you're showing, two things to check:
The model binder is going to look for an object named Header with string property h_dist_cd to bind to. Your action method looks like Header is the root view model and not a child object of your model.
I don't know how you are handling the case where the checkboxes are cleared. The normal trick is to render a hidden field with the same name.
Also a nit, but you want to use 'label for="..."' so they can click the text to check/uncheck and for accessibility.
I've found that using extensions for this problem is error prone. You might want to consider a child view model instead. It fits in better with the EditorFor template system of MVC2.
Here's an example from our system...
In the view model, embed a reusable child model...
[AtLeastOneRequired(ErrorMessage = "(required)")]
public MultiSelectModel Cofamilies { get; set; }
You can initialize it with a standard list of SelectListItem...
MyViewModel(...)
{
List<SelectListItem> initialSelections = ...from controller or domain layer...;
Cofamilies = new MultiSelectModel(initialSelections);
...
The MultiSelectModel child model. Note the setter override on Value...
public class MultiSelectModel : ICountable
{
public MultiSelectModel(IEnumerable<SelectListItem> items)
{
Items = new List<SelectListItem>(items);
_value = new List<string>(Items.Count);
}
public int Count { get { return Items.Count(x => x.Selected); } }
public List<SelectListItem> Items { get; private set; }
private void _Select()
{
for (int i = 0; i < Items.Count; i++)
Items[i].Selected = Value[i] != "false";
}
public List<SelectListItem> SelectedItems
{
get { return Items.Where(x => x.Selected).ToList(); }
}
private void _SetSelectedValues(IEnumerable<string> values)
{
foreach (var item in Items)
{
var tmp = item;
item.Selected = values.Any(x => x == tmp.Value);
}
}
public List<string> SelectedValues
{
get { return SelectedItems.Select(x => x.Value).ToList(); }
set { _SetSelectedValues(value); }
}
public List<string> Value
{
get { return _value; }
set { _value = value; _Select(); }
}
private List<string> _value;
}
Now you can place your editor template in Views/Shared/MultiSelectModel.ascx...
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<WebUI.Cofamilies.Models.Shared.MultiSelectModel>" %>
<div class="set">
<%=Html.LabelFor(model => model)%>
<ul>
<% for (int i = 0; i < Model.Items.Count; i++)
{
var item = Model.Items[i];
string name = ViewData.ModelMetadata.PropertyName + ".Value[" + i + "]";
string id = ViewData.ModelMetadata.PropertyName + "_Value[" + i + "]";
string selected = item.Selected ? "checked=\"checked\"" : "";
%>
<li>
<input type="checkbox" name="<%= name %>" id="<%= id %>" <%= selected %> value="true" />
<label for="<%= id %>"><%= item.Text %></label>
<input type="hidden" name="<%= name %>" value="false" />
</li>
<% } %>
</ul>
<%= Html.ValidationMessageFor(model => model) %>
Two advantages to this approach:
You don't have to treat the list of items separate from the selection value. You can put attributes on the single property (e.g., AtLeastOneRequired is a custom attribute in our system)
you separate model and view (editor template). We have a horizontal and a vertical layout of checkboxes for example. You could also render "multiple selection" as two listboxes with back and forth buttons, multi-select list box, etc.
I think what you need is how gather selected values from CheckBoxList that user selected and here is my solution for that:
1- Download Jquery.json.js and add it to your view as reference:
2- I've added a ".cssMyClass" to all checkboxlist items so I grab the values by their css class:
<script type="text/javascript" >
$(document).ready(function () {
$("#btnSubmit").click(sendValues);
});
function populateValues()
{
var data = new Array();
$('.myCssClas').each(function () {
if ($(this).attr('checked')) {
var x = $(this).attr("value");
data.push(x);
}
});
return data;
}
function sendValues() {
var data = populateValues();
$.ajax({
type: 'POST',
url: '#Url.Content("~/Home/Save")',
data: $.json.encode(data),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function () { alert("1"); }
});
}
</script>
3- As you can see I've added all selected values to an Array and I've passed it to "Save" action of "Home" controller by ajax 4- in Controller you can receive the values by adding an array as argument:
[HttpPost]
public ActionResult Save(int[] val)
{
I've searched too much but apparently this is the only solution. Please let me know if you find a better solution for it.
when you have multiple items with the same name you will get their values separated with coma

A CFML variable name cannot end with a "." character error

I get this error when posting a form. The strangest thing, though, is that this error only occurs in Chrome and Safari. FF, IE and Opera all post the form without a problem.
The Stack Trace does not point to a file to where this error occurs. A cfdump of cfcatch gives me some insight as to what the problem is, but I can't find any instance of where the problem actually exists. Here's the partial dump:
Column 1
Detail The variable attributes. ends with a "." character. You must supply an additional structure key or delete the "." character.
KnownColumn -1
KnownLine -1
KnownText "unknown"
Line 1
Message A CFML variable name cannot end with a "." character.
Here's the code handling the posted data. Everything is wrapped inside cftransaction and there's a loop, not sure why it's not being displayed. (thanks Peter Boughton for clearing that up)
<!--- Delete out the old category ties --->
<cfquery name="deleteCategory" datasource="#request.dsnWrite#">
DELETE FROM
ProductListings_categories
WHERE
listingID = <cfqueryparam value="#attributes.listingID#">
</cfquery>
<!--- Loop through the list --->
<cfloop list="#attributes.taginput#" index="idx" delimiters=".">
<!--- check to see if tag exists --->
<cfquery name="checkTag" datasource="#request.dsnWrite#">
SELECT
categoryID
FROM
categories
WHERE
CategoryName = <cfqueryparam value="#idx#" cfsqltype="cf_sql_varchar">
</cfquery>
<!--- If it does not then add the tag --->
<cfif not(checkTag.recordCount)>
<cfquery name="insertTag" datasource="#request.dsnWrite#">
INSERT into Categories
(
categoryname,
dateCreated
)
VALUES
(
<cfqueryparam value="#idx#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
)
</cfquery>
<cfquery name="insertTag" datasource="#request.dsnWrite#">
SELECT
LAST_INSERT_ID() as newID
FROM
Categories
</cfquery>
<cfset variables.categoryID = insertTag.newID>
<cfelse>
<cfset variables.categoryID = checkTag.categoryID>
</cfif>
<cftry>
<!--- Tie the tag to the listing --->
<cfquery name="insertCategory" datasource="#request.dsnWrite#">
INSERT into ProductListings_categories
(
listingID,
CategoryID
)
VALUES
(
<cfqueryparam value="#attributes.listingID#" cfsqltype="cf_sql_bigint">,
<cfqueryparam value="#variables.categoryID#" cfsqltype="cf_sql_bigint">
)
</cfquery>
<cfcatch></cfcatch>
</cftry>
</cfloop>
<cflocation url="/sell/add_listing/step/3/listingID/#attributes.listingID#" addtoken="false">
Any insight would be great. Thanks!
Here's the form and the Javascript. I haven't had a chance to rewrite the code by the previous developer (up until this point, it was working, so there was no need to visit the code in the first place), but CFFORM isn't used, nor are other CF form items. Various JS functions are used for AJAX calls and are included as well.
<form action="/sell/add_listing/step/2/listingID/#attributes.listingId#" method="post">
<div id="formFields"><input name="tagInput" id="tagInput" value="#variables.tagInput#" type="hidden"/></div>
<h3>Step 2: <span id="instructions">First, choose a top-level category</span></h3>
<p id="instructions2">This category will show up as the first tag on your listing.</p>
<div id="tagLand">
<div>
1. <select onchange="mainCategorySelector(this.value)">
<cfloop query="getTopCats">
<option value="#getTopCats.categoryName#" <cfif ListFirst(variables.tagInput,".") EQ getTopCats.categoryName>selected="selected"</cfif>>#capFirstTitle(ReplaceNoCase(getTopCats.categoryName, "_"," ", "all"))#</option>
</cfloop>
</select>
</div>
<div id="inputDiv" style="visibility: hidden;">
<div>Add a tag</div>
<div>2.
<input type="text" onkeypress="return disableEnterKey(event)" name="newTag" id="newTag" maxlength="18"/>
<input type="button" value="add" onclick="addTag(document.getElementById('newTag').value)" class="small_button" />
</div>
<div class="error"></div>
</div>
</div>
<img src="/resources/img/layoutV3/button_prev.gif" alt="prev"/>
<input type="image" name="btnSubmit" src="/resources/img/layoutV3/button_next.gif" />
</form>
<script src="/resources/js/listing_2.js" type="text/javascript"></script>
//some variables
var listCount=1;
var tagLimit=14;
var maxSuggestions=100;
var allTags=new Array();
var allTags=new Array();
var allTagPointers=new Array();
var currentTags=0;
// XML document
var xmlDoc;
var req;
//this function will run anything upon page load
function addLoadEvent(func)
{
var oldonload = window.onload;
if (typeof window.onload != 'function')
{
if(func)window.onload = func;
}
else
{
window.onload = function()
{
oldonload();
func();
}
}
}
//let's rebuild the page!
addLoadEvent(rebuildTags());
function rebuildTags()
{
//grab the tag tree left for us by PHP
var passedTags=document.getElementById('tagInput').value;
//only run if we got a value
if(passedTags.replace(/^\s+|\s+$/g, ""))
{
//split the string into an array
passedTags=passedTags.split(".");
//run functions to rebuild the world
mainCategorySelector(passedTags[0]);
for(var i=1;i<passedTags.length;i++)
{
addTag(passedTags[i]);
}
}
}
function addTag(tagName)
{
tagName=trim(tagName);
tagName=tagName.toLowerCase();
if(tagName)
{
//remove underscores from tags, replace with spaces so we can validate
tagName=tagName.replace(/_/g," ");
//clear out error message if it's there
var errorDiv=document.getElementById('errorDiv');
errorDiv.innerHTML="";
//only run if we're not at the limit and tag has not been used already
if(currentTags<=tagLimit && !getArrayIndex(allTags,tagName))
{
//if not alphanumeric, error
var myRegxp = /^[0-9a-zA-Z\s]*$/;
if(myRegxp.test(tagName)==false)
{
var errorDiv=document.getElementById('errorDiv');
errorDiv.innerHTML="You may only use letters and numbers in your tags.";
}
//if it error checks fine, move on
else
{
//let's replace all spaces with underscores for DB storage
//tagName=tagName.replace(/ /g,"_");
//query server and get list of related tags
//random number to kill the cache
var cacheKiller=Math.random();
//get all children tags
xmlDoc=ajaxRequest("/sell/get_categories_xml/tag/"+tagName.replace(/ /g,"_")+"/random/"+cacheKiller);
relatedTags=new Array;
var root=xmlDoc.getElementsByTagName('root')[0];
var tags=root.getElementsByTagName('tag');
//now get all sibling tags
xmlDoc=ajaxRequest("/sell/get_categories_siblings_xml/tag/"+tagName.replace(/ /g,"_")+"/random/"+cacheKiller);
root=xmlDoc.getElementsByTagName('root')[0];
var siblingTags=root.getElementsByTagName('tag');
//first compile child tags into an array
for(var i=0;(i<tags.length && i<maxSuggestions);i++)
{
relatedTags[i]=tags[i].firstChild.nodeValue;
}
//now add sibling tags to the same array
tags=root.getElementsByTagName('tag');
for(i;(i<tags.length && i<maxSuggestions);i++)
{
relatedTags[i]=tags[i].firstChild.nodeValue;
}
var tagLand=document.getElementById('tagLand');
var newNumberDiv=document.createElement('div');
var newDiv=document.createElement('div');
//add to counter and master tag array
listCount++;
allTags[allTags.length]=tagName.replace(/ /g,"_");
allTagPointers[allTagPointers.length]=listCount;
updateForm();
newNumberDiv.setAttribute('id','number_'+listCount);
newNumberDiv.className='listing_number';
newNumberDiv.innerHTML=listCount+".";
newDiv.innerHTML=tagName+' <span onclick="removeTag(\''+listCount+'\');" class="list_dynamic_link">x</span>';
newDiv.className='list_tag';
var newReccomendDiv=makeRelatedDiv(relatedTags);
//let's give IDs to all of the new divs so we can't kill 'em later
newDiv.setAttribute('id','tagDiv'+listCount);
newReccomendDiv.setAttribute('id','reccomendDiv'+listCount);
//add new divs to the master list
tagLand.appendChild(newNumberDiv);
tagLand.appendChild(newDiv);
tagLand.appendChild(newReccomendDiv);
//remove and re-append the input div to keep it at the end
var inputDiv=document.getElementById('inputDiv');
tagLand.removeChild(inputDiv);
tagLand.appendChild(inputDiv);
//make the inputDiv visible if it is not already
inputDiv.style.visibility='visible';
//run the reorderizer
reorderizer();
//clear input field
document.getElementById('newTag').value="";
document.getElementById('newTag').focus();
}
}
}
}
//removes a tag from the list -- called through the "x" link on each tag
function removeTag(tagNumber)
{
//get master div
var tagLand=document.getElementById('tagLand');
//get reference to all three divs that make up a tag listing
var deathRowNumberDiv=document.getElementById('number_'+tagNumber);
var deathRowTagDiv=document.getElementById('tagDiv'+tagNumber);
var deathRowReccomendDiv=document.getElementById('reccomendDiv'+tagNumber);
//any last words, boys?
tagLand.removeChild(deathRowNumberDiv);
tagLand.removeChild(deathRowTagDiv);
tagLand.removeChild(deathRowReccomendDiv);
//find where we are in the master array
var tagIndex=getArrayIndex(allTagPointers,tagNumber);
//splice this tag out of master tag array
allTags.splice(tagIndex,1);
allTagPointers.splice(tagIndex,1);
updateForm();
//alert(allTags.join("."));
//since we just changed the page structure, let's run reorderizer
//run the reorderizer
reorderizer();
//make the inputDiv visible if we're below the tag limit
var inputDiv=document.getElementById('inputDiv');
if(currentTags<=tagLimit)
{
inputDiv.style.visibility='visible';
}
}
//this function displays the formatted div for related tags
function makeRelatedDiv(relatedTags)
{
//let's prepare the recommended tags div
var newReccomendDiv=document.createElement('div');
newReccomendDiv.className='list_suggested_tags';
newReccomendDiv.innerHTML='<span>Add related tags: </span> ';
var numTags=0;
//loop through suggested tag array
for ( keyVar in relatedTags )
{
//add comma if necessary
if(numTags)
{
newReccomendDiv.innerHTML+=", ";
}
newReccomendDiv.innerHTML+='<span onclick="addTag(\''+relatedTags[keyVar]+'\');" class="list_dynamic_link">'+relatedTags[keyVar]+'</span>';
numTags++;
}
return newReccomendDiv;
}
function mainCategorySelector(tag)
{
//only run if we're not the dead selection
if(tag!="- - -")
{
//query server and get list of related tags
//random number to kill the cache
var cacheKiller=Math.random();
xmlDoc=ajaxRequest("/sell/get_categories_xml/tag/"+tag+"/random/"+cacheKiller);
relatedTags=new Array;
var root=xmlDoc.getElementsByTagName('root')[0];
var tags=root.getElementsByTagName('tag');
for(var i=0;(i<tags.length && i<maxSuggestions);i++)
{
relatedTags[i]=tags[i].firstChild.nodeValue;
}
var tagLand=document.getElementById('tagLand');
var newReccomendDiv=makeRelatedDiv(relatedTags);
//replace old reccomend list if it exists
if(document.getElementById('mainCategoryReccomendations'))
{
var mainCategoryReccomendations=document.getElementById('mainCategoryReccomendations');
tagLand.appendChild(newReccomendDiv);
tagLand.insertBefore(newReccomendDiv , mainCategoryReccomendations);
tagLand.removeChild(mainCategoryReccomendations);
}
else
{
tagLand.appendChild(newReccomendDiv);
//add to counter if we added a new tag
listCount++;
}
newReccomendDiv.setAttribute('id' , 'mainCategoryReccomendations');
//alert(allTags.join("."));
//add master tag array
allTags[0]=tag;
allTagPointers[0]=1;
updateForm()
//alert(allTags.join("."));
//remove and re-append the input div to keep it at the end
var inputDiv=document.getElementById('inputDiv');
tagLand.removeChild(inputDiv);
tagLand.appendChild(inputDiv);
//make the inputDiv visible if we're below the tag limit
if(currentTags<=tagLimit)
{
inputDiv.style.visibility='visible';
//focus on the new field
document.getElementById('newTag').focus();
}
//change up the instructions
changeInstructions("Now, add other tags to sort your listing","You can either click the related tags or enter your own")
}
}
//this function changes the content of the instructional div
function changeInstructions(top, bottom)
{
var instructions=document.getElementById('instructions');
var instructions2=document.getElementById('instructions2');
instructions.innerHTML=top;
instructions2.innerHTML=bottom;
}
//this function reassigns all list numbers to their proper value
function reorderizer()
{
/*
Here we run through all number div IDs...
remember, the div ID number may not match the display number, due to
additions/removals. That's why we have a separate variable for displayNumber!
*/
var tagLand=document.getElementById('tagLand');
//another counting var, for the actual display number
var displayNumber=1;
for(var i=1; i <= listCount; i++)
{
if(document.getElementById('number_'+i))
{
var b=document.getElementById('number_'+i);
b.innerHTML=displayNumber+".";
//ony increment displayNumber if we've actually printed a number
displayNumber++;
}
}
//update global tag count to most current and accurate number
currentTags=displayNumber;
//have we hit the tag limit? If so, hidezorz input
if(displayNumber>tagLimit)
{
var inputDiv=document.getElementById('inputDiv');
inputDiv.style.visibility='hidden';
}
else
{
//after looping through dynamic list entries, let's change the submit field's number too
var number_last=document.getElementById('number_last');
if(number_last)
{
number_last.innerHTML=displayNumber+".";
}
}
}
function pausecomp(millis)
{
date = new Date();
var curDate = null;
do { var curDate = new Date(); }
while(curDate-date < millis);
}
function ajaxRequest(requestURL)
{
var req;
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.open("GET", requestURL, false);
req.send(null);
var xmlDocument = req.responseXML;
return(xmlDocument);
}
function disableEnterKey(e)
{
var key;
if(window.event)
key = window.event.keyCode; //IE
else
key = e.which; //firefox
if(key == 13)
{
addTag(document.getElementById('newTag').value);
return false;
}
else
{
return true;
}
}
function getArrayIndex(arr, val)
{
for (i = 0; i < arr.length; i++)
{
if (arr[i] == val) { return i; }
}
}
function updateForm()
{
//this function updates the hidden field that will actually send the tag data upon form submission
document.getElementById('tagInput').value=allTags.join(".");
}
Problem solved: select list did not have the name attribute defined, and as a result, the attributes variable did have a null field name, causing the error. In my case, the select list is not used in CF, but only in JS. Chrome and Safari will pass a field's value even if the field lacks a name, while IE, FF and Opera do not. Thanks for guiding me in the right direction.
From your description it sounds like that the error is thrown by the form itself in the client, and not the handling code that you've posted above. If you have a cfform/cfgrid on the calling page, you may want to look at the Javascript that's generated by CF and test it against Chrome/Safari.