Hi I was following a tutorial on sitepoint for creating structs. I must be missing something since I followed the code exactly, but keep getting an error!

Here is the code:

<cfset myBook= structNew()>
<cfset a = StructureInsert(myBook, \\"title\\", \\"All About Coldfusion\\", 1)>
<cfset a = StructureInsert(myBook, "author", "Teed Younger", 1)>
<cfset a = StructureInsert(myBook, "description", "Information About CF", 1)>
<cfset a = StructureInsert(myBook, "publishYear", "2005", 1)>
<cfset a = StructureInsert(myBook, "ISBN", "ABCD123456", 1)>


<cfoutput>
Title: #myBook["title"]#<br />
Author: #myBook["author"]#<br />
Description: #myBook["description"]#<br />
Published: #myBook["publishYear"]#<br />
ISBN: #myBook["ISBN"]#
</cfoutput>

The error says I have a missing arguement and cites line 10, but I dont see what I am missing. I also dont understand what the backslashes are for in the title struct. When I take them out to match the other structureInserts, it gives another error saying I haven't defined structureInsert. I am new to learning structs so any help is greatly appreciated!

Recommended Answers

All 38 Replies

I followed the code exactly

I hope not ... because that code is wrong :) Two things are messing it up
1) Assuming the \\ is not a typo. Get rid of them.
2) The function is StructInsert ... not StructureInsert

But that function isn't used as much as it used to be. Most times it's simpler to just use array notion. That's my preference. But all of these are valid

<cfset StructInsert(myBook, "author", "Teed Younger", true)>
   ... or ....
   <cfset myBook.author = "Teed Younger"> 
   ... or ....
   <cfset myBook["author"] = "Teed Younger">

<cfset a = StructureInsert(myBook, "author", "Teed Younger", 1)>

It's not the cause of the error, but there's no need to capture the result if you're not using it.

<cfset StructInsert(myBook, "author", "Teed Younger", true)>

Btw, where is this tutorial? It sounds outdated.

lol I'm so dumb! lol Seriously I do think I'm getting dyslexic!!

Changed the structureInsert(which I could have sworn I saw!!) and now its correct function.

The backslashes are actually there in the tutorial! I swear...lol

Yes it may be outdated and yes I'm sure this way is not the best way to do it, but I'm thinking as the tutorial goes along, they will be using more modern approaches.

Here is the tutorial.

Figures the back slashes are actually in the code. lol. That one must have gotten past the editor.

Yeah, the article is definitely outdated. Most of it still applies. But StructInsert isn't as commonly used now as it was in 2003 Nowadays most people just use array notation. Simpler and more intuitive.

For the lazy, there's even shortcuts in CF8+. So instead of doing

<cfset myBook = structNew()>
<cfset myBook.publishYear = "2005">
<cfset myBook.ISBN= "ABCD123456">

You can do it all in one line

<cfset myBook = {publishYear = "2005", ISBN= "ABCD123456"}>

But it's mostly personal preference. For long structures, the line by line approach is perfectly fine.

1) <cfset myBook.author = "Teed Younger">
... or ....
2) <cfset myBook["author"] = "Teed Younger">

Personally, I prefer syntax 1 (dot notation). Either is okay unless your key name isn't a valid variable name. Like it has spaces or dashes in it ie myBook["some-author"]. Then you must use syntax 2.

Well this all started because I was trying to figure out how to display text in a dynamci list. I started another thread here asking about it. On another forum I was told how bad the way I was doing this was....to which I agreed, but since I myself have no experience in jQuery or ajax, I declinded to use the suggestion someone provided. Then they worked up a demo for me and gave me the code. I said it was way over my head but I would love to use it. After two and a half days of trying to understand it, I asked for more help in understanding how to pass the values on the form input fields to my action page. I was told he didnt feel like helping me anymore..lol

Anyway, so since I need to start learning this anyway, I thought I better get to it..lol

ahhh lol shoulda known you were the one helping me in my last post "Another way to do this" so you're familiar with what I'm trying to do.

I have that version of what I was trying to code working fine, but as you know and we discussed, its a nightmare for the person entering the data. Keeping which delimiter goes where, when to hit enter, when to just let a soft return happen.

Yeah, I saw that thread. Being fair that's not what he was saying :P I think the questions were just to broad/ambiguous to be answered. I know some of the background, and even I was intimidated by the sheer scope of it ;-) No joke, I wasn't even sure what the question was .. let alone where to begin trying to answer it.

I think we both love learning and teaching. But there's only so much you can do in a forum post. Forums are good for small, specific questions. Broad comments like "how do I make it work" or "tried everything, and nothing works" aren't questions that can be answered. They just sound like someone is asking others to write the code for them. I know that not's what you were doing. I'm just trying to explain why they responded the way they did. I think if you'd tried the code, and come back with a specific problem (however small), the response would have been better.

I hope you didn't take my remarks the wrong way. I just didn't have a clue where to begin with your question on the other forum. As strange as it sounds, it was as overwhelming to me as jquery probably is to you right now ;-)

Oh no...no problem. I think your last post confused me somewhat though..lol

My last post was in reference to a thread I started on adobe's forums, where I got some code from someone. Yes I probably did sound too generic when I posted I was lost and needed help understanding the code. I guess I should have been more specific and specified a legitimate question about a certain issue. I actually thought thats what I had done. Even though I didnt understand much of the code he gave me, I thought I could at least figure out how to display the form inputs on my action page. Not so easy....lol I mean most of his code is jQuery written just to dynamically create controls or objects, for lack of knowledgeable working.

But I guess I took his response as him being highminded. I said I wasnt mad, and I'm not, but just felt like if someone tells you your doing something wrong and then offers some code for you to "use", then they ought to be willing to help you further long if you've already said "it's over my head".

I've been working all day off and on trying to learn structs and arrays of structs, and have a somewhat good understanding. Now I just need to figure out how to display the struct his code contains, along with the form input values on my action page.

Anyway, no worries. You've been a great help to me here! As I said before, I wish there were more Coldfusion forums, and more activity on the few that are around.

lol. The confusion is spreading ;-)

But I guess I took his response as him being highminded. I said I wasnt mad, and I'm not, but just felt like if someone tells you your doing something wrong and then offers some code for you to "use", then they ought to be willing to help you further long if you've already said "it's over my head".

Yeah, but you have to articulate "what specifically" you need help with :-) ie "I've tried X code and expected Y results. But instead I'm getting Z results." Otherwise people don't know how to answer you. Or worse it sounds like saying "write the code for me". I admit the guy was definitely blunt. But I don't think he was trying to be a jerk. Otherwise, he wouldn't have bothered putting together a custom example for you in the first place :-)

I'm not a jquery guru. So I don't completely understand his sample either. But if it were me, I'd run the example and post it to an action page. Then dump the results and go from there. If it's just structures and arrays, which I think it is, it might not be so bad and I might actually be able to help!

Hey, I just tried it .. and that's a fantastic example! I'm not smart enough to write it, but it's great. Everything's organized into a structures and arrays. Just loop through it and extract what you need.

lol yes its a great application! And thats what I'm trying to do...I just dont know enough about struct and arrays...AND how to display user defined values of structs and arrays yet to get it working.


Still learning though.

It's actually pretty easy. Just deserialize the results.

<cfset results = deserializeJSON(url.data)>

Each "item" is a structure. They "key" is the item name, and the "value" are the details (category, vendors, etc..). So loop through it like in the sitepoint article.

<cfloop collection="#results#" item="itemName">
    <cfset item = results[itemName]>
    <cfdump var="#item#" label="Item Name #itemName#">
</cfloop>

If you look at the dump of each "item", that structure contains 2 keys: "category" and "vendors". Category name is a simple string you can access using #item.category#

Now "Vendors" is another structure. The "key" is a vendor name and the "value" is an array of products. To extract the values, loop through it the same way

<cfloop ....>
   ... 
   <cfloop collection="#item.vendors#" item="vendorName">
       <cfset productArray = item.vendors[vendorName]>   
       <cfdump var="#productArray #" label="Products for vendor: #vendorName#">
   </cfloop>
  ...
</cfloop>

Then loop through the product array to get each value. For CF8+ it's a simple "array" loop

....
   <cfloop array="#productArray #" index="productName">
       ...do something with #productName#....
   </cfloop>
....

Obviously you have to *do* something with the values. But now that you see how to extract them, the rest is easy.

Ok, I think I have it working..lol. One question though. Is there a way to alphabetize the dynamic lists?. As it is now, it seems that if you populate one item then go back and add another item, it puts the second one at the top of the output.


Thanks again for all your help!! I still dont quite understand structs like this, I do have a basic understanding, but I'll keep reading and playing around with them.

ok well I have the code working as I want, and displaying in a list as well.

However, when I pull the code into my application....my pageTemplate.cfm and pull the the cfloops over to MY action page, I get an error saying data is undefined.

I was thinking I needed to pass the FORM variables, but that doesnt seem to work either. I dont know...lol I'm pretty confused at this point.

My whole application is reliant on SESSION and FORM variables, then to throw this into the mix makes it even more confusing.

I've no idea what your final code looks like. So I'm not sure what to suggest :)

Well here is the link to the whole application. The template.cfm is where the user enters all her data, then when she clicks submit, it takes her to the action page so she can preview how the page will look before finalizing the .html page and saving to a specified folder on our network.


When I throw a cfdump of #results# before the cfoutput for my loop it says [empty string]

Well think about it :) Your code isn't doing the same thing as the example. The example sends data via ajax and displays the results w/out even leaving the current page. You're doing a form post, which obviously leaves the page. Not to mention sends the data in the FORM, not URL, scope. So obviously the sample code won't work.

Well thats what I saying above. I figured I somehow needed to pass the form variables.

I'm about ready to scrap this jQuery code. It has me so confused now I dont even know what my original application is doing..lol.

Your choice. I think you're totally misunderstanding how the example's supposed to work, lol. Forget about the code for a sec and think about what the 2 pieces of code are doing conceptually.

You're trying to do it old style
page1.cfm => go to => page2.cfm to see preview

The whole point of ajax is to avoid leaving the page. So users can see preview changes quickly, and you don't have to worry about maintaining the state form page to page. Technically you still send data to page2.cfm. But you display the results on the original page. It's no more complex than updating the content of an element with javascript.

document.getElement('myDiv').innerHTML = "See I just changed the content!";

Well I know ajax does just that, it changes page data or whatever without making a new request to the server.


So with that said, I went back to the original example he gave me, changed the action.cfm to my builderAction.cfm and ran the script from there. Works just fine like that. It "adds" the list items like it should and "loads" my builderAction.cfm without a page refresh.

So, why then couldnt I take the code...jquery/ajax...out of that page, paste it into my template, using the same builderAction.cfm "action" within the ajax function, and display it that way.

lol. I didn't mean to sound like you don't know how ajax works. Just that you weren't using the form as it was intended to work. ie You were using a submit button to do a plain form post the old way. Instead of a plain button to do an ajax call (method=get) and display the content on the same page.

So, why then couldnt I take the code...jquery/ajax...out of that page, paste it into my template, using the same builderAction.cfm "action" within the ajax function, and display it that way.

Sorry .. I'm brain dead today. Not sure what you mean by template. ie Are you talking about having everything (jquery and action) on the same page? That should work as long as you structure it correctly.

lol no I wasn't trying to sound like you were trying to sound like I didnt know what ajax was for...lol

Sorry .. I'm brain dead today. Not sure what you mean by template. ie Are you talking about having everything (jquery and action) on the same page? That should work as long as you structure it correctly.

I think maybe therein lies the problem. My form submit button.

let me post the relavant parts of my template.cfm page. I guess when I said template, that was confusing. I should probably change that name.

Here is how I thought this would work with my CURRENT page and action page.

Here is the jQuery code. Notice the ajax function and the action page file its calling.

<script src="http://www.google.com/jsapi"></script>
<script> 
// Load jQuery
google.load("jquery", "1.4.2");
 
google.setOnLoadCallback(function(){
	$(document).ready(function(){
		$('.add-product').live('click', function(){
			var productContainer = $(this).parents('.product');
			var newProduct = $(productContainer).clone();
			$(newProduct).find('.product-input').val('');
			
			var vendorProductContainer = $(productContainer).parents('.vendor-products');
			$(vendorProductContainer).append(newProduct);
			$(productContainer).find('.add-product').hide();
						
			return false;
		});
		$('.add-vendor').live('click', function(){
			var vendorContainer = $(this).parents('.vendor');						
			//clone the vendor
			var newVendor = $(vendorContainer).clone();
			$(newVendor).find(':input').val('');
			
			//remove all but the first products
			$(newVendor).find('.product:gt(0)').remove();
			
			$(vendorContainer).after(newVendor);
			$(newVendor).find('.add-product').show();
			$(vendorContainer).find('.add-vendor').hide();
			return false;
		});
		
		$('#submit').click(function(){
			$('#results').html('Loading...');
			
			var items = {};
			
			$('.product-grouping').each(function(i,e){
				var title = $(e).find('legend').html();
				items[title] = {};
				items[title]['category'] = $(e).find('.category').val();
				items[title]['vendors'] = {};
				$(e).find('.vendor').each(function(vi,ve){
					var products = [];
					var v = $(ve).find('.vendor-input').val() || 'vendor ' + (vi+1);
					
					$(ve).find('.product-input').each(function(pi,pe){
						products.push($(pe).val());
					});
					items[title]['vendors'][v] = products;
				});
				
			});
			
			$.ajax({
				type: 'GET',
				url: 'pageBuilder/builderAction.cfm?data=' + JSON.stringify(items),
				dataType: 'html',
				complete: function(data){
					$('#results').html(data.responseText);
				}
			});
							
		});
		
		$('#add-item').click(function(){
			var item = $('.product-grouping:last').clone();
			$(item).find('.vendor:gt(0)').remove();
			$(item).find('.product:gt(0)').remove();
			$(item).find(':input').val('');
			$(item).find('.add-product').show();
			$(item).find('.add-vendor').show();
			var itemIdx = $('.product-grouping').size() + 1;
			$(item).find('legend').html('Item ' + itemIdx);
			$('#items').append(item);
		});
		
	});
});
</script>

here is the form code on the same page template.cfm:

<form method="POST">
		<div id="items">
			<fieldset class="product-grouping">
				<legend>Item 1</legend>
											
				<div class="vendor" style="padding-left: 30px;">
					<span>Vendor: </span>
					<input type="text" class="vendor-input" name="vendor" />
					<a href="#" class="add-vendor">add vendor</a>
					
					<div class="vendor-products" style="padding-left: 60px;">
						<div class="product">
							<span>Product: </span>
							<input type="text" class="product-input" name="product" />
							<a href="#" class="add-product">add product</a>
						</div>
					</div>
				</div>
				
			</fieldset>
		</div>
		
		<input type="button" id="add-item" value="add item" />
		<input type="button" id="submit" value="submit" />
	</form>

Now one thing I will mention is that I have other form elements on this page. Therefore, I think as you suggested, if I am trying to submit SOME form input elements as a regular form action post, and I have this ajax function that gets the data and displays it via a javascript button, I guess thats going to be in conflict.

Then finally here is my cfloop displaying the data on builderAction.cfm:

<cfoutput>
          <cfset results = deserializeJSON(url.data)>
          <!--- <cfdump var="#results#"> --->
          <cfloop collection="#results#" item="itemName">
            <cfset item = results[itemName]>
            <cfdump var="#item#" label="Item Name #itemName#">
            <cfloop collection="#item.vendors#" item="vendorName">
              <ul>
                <li>
                  <h2>#vendorName#</h2>
                </li>
                <cfset productArray = item.vendors[vendorName]>
                <!--- <cfdump var="#productArray#" label="Products for vendor: #vendorName#"> --->
                <cfloop array="#productArray#" index="productName">
                  <li>#productName#</li>
                </cfloop>
              </ul>
            </cfloop>
          </cfloop>
        </cfoutput>

Again, this whole thing works as long as I dont try to do it the old way as you said. When I use the original two files he gave me....objectTest.cfm and action.cfm....then it works.

Now one thing I will mention is that I have other form elements on this page.

Yeah, but they're not inside the same <form> right? So you could process that form data separately, like have a "preview" and "submit" button for just that form.

Well I tried that.,...I think...lol. I clicked the ajax function button which outputted the "list" as needed, but then when I click my page submit button, I still got a data undefined error.

What I did though was I have this code/form inside my old form. That might make the difference. Still though, if my action page is looking for a vaque for the element of data, not sure that would work either. Gonna try anyway.

Nope....same error..lol

Pretty much the whole page is a form to submit cfinputs and pass the form values to my action page. I closed the cfform right before this jQuery form for the lists. So then I go down, populate my dynamic list, click submit, the values are displayed, then I lcick my page submit button.

hmmm...both submits action is to the builderAction.cfm. Maybe I need another "go between" action page?

No scratch that. The jQuery form action is the original action.cfm which just displays the results without a refresh. Then the page form action os to builderAction.cfm. I guess I need to somehow capture the values of the list, which I just thought would be straight html.

Well I tried that.,...I think...lol. I clicked the ajax function button which outputted the "list" as needed, but then when I click my page submit button, I still got a data undefined error.

Right. Because that variable doesn't exist... The ajax function and your <form> *don't* send the same data the same way

Ajax uses-> URL scope
Your <form> uses-> FORM scope

Ajax sends a complex structure -> URL.data[ItemName].vendorName ...etc...
Your <form> sends simple strings -> FORM.vendor, FORM.product, etc..

ie exactly what's in your <form>
<input type="text" class="vendor-input" name="vendor" />
<input type="text" class="product-input" name="product" />

You can't just plug the ajax into a larger <form>, POST it have it work right out of the box. You won't get an error, but your code isn't set up to handle it. It's something you have to add.

At this point I'm totally lost ;-/ ... I thought you were trying to do a simple preview of JUST the vendor/product stuff. But it's starting to sound like much more than that ... There's a lotta stuff on that page you linked. If you're trying to incorporate this section (vendors/products) with that whole big form .. you've got your work cut out for you. I'm sure it's possible, but it's beyond my skills. And with my brain mainly focused on my work, I've kinda lost track of what you're trying to do at this point ;-)

I really do appreciate how much you've helped me! lol I guess what I know in my head of how I want something to work....how I want one thing to work with another thing...here two different pieces and types of code, is one thing. Translating it to a forum like this so that someone would understand perfectly is another thing.

Ajax sends a complex structure -> URL.data[ItemName].vendorName ...etc...Your <form> sends simple strings -> FORM.vendor, FORM.product, etc..

Yes that makes sense and now that you explained it, I do understand the difference. I'll keep working on it for now. I may not know alot of code like this, but one thing I have learned is that almost nothing is impossible in coding of one form or another...lol There has to be a way.

Thanks again for all your patience and help!

If I knew more jquery I'd say change it make the field names unique. Then you could process it easily as product1,product2, etc.. But that's beyond my skills for now ;)

Yeah, there's an art to asking a "good" question. I'm fine with small stuff. But I really suck asking about big conceptual stuff. lol. Usually people have no clue what I mean. Some people are amazing at it. Their descriptions simple and concise. They get great answers ... when I couldn't even form the question...let alone the answer. lol

Btw ... if you're going to open another question on this, I'd suggest including *exactly* what you happen, with specific variable and field names, etc.. Don't make the reader guess ;-)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.