Jump to content

Editing table cell inline


briandaly40

Recommended Posts

Hi all,

 

I need to create a table whereby a user can click on a cell to edit its contents in PHP. Once entered, the rest of the cells in that row should recalcuate depending on what value was entered. I am hoping to prevent the page from loading everytime a change is made so I am trying to use AJAX.

 

I have been working on it for some time but can't figure out a solution.

 

My approach is as follows:

When a user opens the page first, a few arrays are created to store the default values of the table. This is then stored in the Session. I then create the table putting the correct array value from the session in the <td> </td>.

 

In each <td> I use Moo Tools to allow editable content on click as follows:

<td class="editable" rel="0">Content</td>

Moo Tools picks up the "editable" class and allows users to edit inline.

 

It then sends a request to a php page with parameters (which array, index to update, content to insert) that allow it to update the session.

 

When this succeeds an AJAX method is called to loop through the arrays and echo out a table with the new, updated data.

This table is then inserted in the div where the old table was.

 

This approach works very well but once I make a change to a cell and the new table overwrites it I cant edit another cell. Its as if Moo Tools lost its event handlers for the "editable" class even though the updated table inserts the class into its <td> 's.

 

Can anyone help me with this issue.

Or is there a better way of achieving the same result.

 

Im starting to think it is beyond my programming skills.

 

All help welcome,

 

Thanks in advance,

briandaly40

Link to comment
Share on other sites

Not really sure how this is a PHP issue, but on the AJAX call back are you setting the table class attribute to editable? If not try to do that and see if it works, as it may need to have that attribute reset since it is a new field.

 

Without seeing any code, especially the code that generates the returned table cell, it will be hard to provide quality help. Either way I fail to see how this is PHP and moving it to AJAX forum.

Link to comment
Share on other sites

MooTools is not constantly watching the dom for elements with the editable class. It reads it in when it loads so it doesnt see your new/updated elements.  You need to look for a MooTools plugin like the jQuery livequery plugin which should fix your issue. The other solution would be to run the MooTools function after the table is added to the dom each time.

Link to comment
Share on other sites

@premiso:

My apologies, I should of posted in the Javascript forum.

The AJAX callback had the class="editable" in it.

 

@JustLikelcarus:

Thanks for your response, you sent me on the right track. I looked for a MooTools version of LiveQuery but I was unable to find one. I then came across Event Delegation.

 

This is where you attach events to a parent (and subsequently, its children) instead of assigning them to each element individually.

 

Attaching the event to the parent means if any elements are injected into the page, they will get attached also.

 

My only problem now is combining my original way and the new way:

 

Original way:

window.addEvent('domready', function() {
		//find the editable areas
		$$('.editable').each(function(el) {
			//add click and blur events
			el.addEvent('click',function() {
				//store "before" message
				var before = el.get('html').trim();
				//erase current
				el.set('html','');
				//replace current text/content with input or textarea element
				if(el.hasClass('textarea'))
				{
					var input = new Element('textarea', { 'class':'box', 'text':before });
				}
				else
				{
					var input = new Element('input', { 'class':'box', 'value':before });
					//blur input when they press "Enter"
					input.addEvent('keydown', function(e) { if(e.key == 'enter') { this.fireEvent('blur'); } });
				}
				input.inject(el).select();
				//add blur event to input
				input.addEvent('blur', function() {
					//get value, place it in original element
					val = input.get('value').trim();
					el.set('text',val).addClass(val != '' ? '' : 'editable-empty');

					//save respective record
					var request = new Request({
						method:'get',
						url:'sessionupdater.php',
						onSuccess: function() {
							showResults();
						}
					}).send('section=' + el.get('section') + '&i=' + el.get('rel') + '&content=' + el.get('text'));
				});
			});
		});
	});

 

New method:

window.addEvent('domready', function() {
$('#results').click(function(event) {
	var $tgt = $(event.target);
	if ($tgt.is('td')) {
		// Do work here...
	}
});
});

 

 

I tried combining the two as follows:

window.addEvent('domready', function() {
		$('#results').click(function(event) {
			var $tgt = $(event.target);
			if ($tgt.is('td')) {
				$$('.editable').each(function(el) {
			//add click and blur events
			el.addEvent('click',function() {
				//store "before" message
				var before = el.get('html').trim();
				//erase current
				el.set('html','');
				//replace current text/content with input or textarea element
				if(el.hasClass('textarea'))
				{
					var input = new Element('textarea', { 'class':'box', 'text':before });
				}
				else
				{
					var input = new Element('input', { 'class':'box', 'value':before });
					//blur input when they press "Enter"
					input.addEvent('keydown', function(e) { if(e.key == 'enter') { this.fireEvent('blur'); } });
				}
				input.inject(el).select();
				//add blur event to input
				input.addEvent('blur', function() {
					//get value, place it in original element
					val = input.get('value').trim();
					el.set('text',val).addClass(val != '' ? '' : 'editable-empty');

					//save respective record
					var request = new Request({
						method:'get',
						url:'sessionupdater.php',
						onSuccess: function() {
							showResults();
						}
					}).send('section=' + el.get('section') + '&i=' + el.get('rel') + '&content=' + el.get('text'));
				});
			});
		});
			}
		});
	});

 

But with this, when someone clicks on a <td> it then adds a click event to each element with an .editable class. Which is like a bad way of implementing on double click.

 

Can someone point out a better solution?

Link to comment
Share on other sites

There isnt a need to combine them.  Just when a click occurs check that it is a 'td' and has the class editable.  Sorry I should have mentioned event deligation before.  It is indeed the best way and requires only one bind instead of one for every td.

 

Cheers JustLikeIcarus,

 

But I am still having trouble with the moo tools event handler.

If you look at the code I posted above. I have the original way, which uses "$$('.editable').each(function(el)" where you can then use el to access methods and properties. For instance in the code I use "el.hasClass('textarea'))". But as I dont use the each method using event delegation I cant use el in my code.

 

In the new method, i say "var $tgt = $(event.target);" to access the element but I need the el for methods such as el.set() or el .hasClass()

 

Does anyone have an idea how I can get this to work. My mootools/js skill are not up to scratch.

 

Thanks!

Link to comment
Share on other sites

Im a jQuery man myself however I am sure its the same in MooTools that when using .each() the element is referenced via $(this). instead of an argument in the function.

 

Again, thanks for the reply.

But I dont want to use .each() anymore as I am now using event delegation. Or am I going about this is the completely wrong way, using the $(this) reference here is what I've got but it doesnt work:

 

window.addEvent('domready', function() {
		$('#results').click(function(event) {
			var $tgt = $(event.target);
			if ($tgt.is('td')) {
				//store "before" message
				var before = $(this).get('html').trim();
				//erase current
				$(this).set('html','');
				//replace current text/content with input or textarea element
				if($(this).hasClass('textarea'))
				{
					var input = new Element('textarea', { 'class':'box', 'text':before });
				}
				else
				{
					var input = new Element('input', { 'class':'box', 'value':before });
					//blur input when they press "Enter"
					input.addEvent('keydown', function(e) { if(e.key == 'enter') { this.fireEvent('blur'); } });
				}
				input.inject($(this)).select();
				//add blur event to input
				input.addEvent('blur', function() {
					//get value, place it in original element
					val = input.get('value').trim();
					$(this).set('text',val).addClass(val != '' ? '' : 'editable-empty');

					//save respective record
					var request = new Request({
						method:'get',
						url:'sessionupdater.php',
						onSuccess: function() {
							if (($(this).get('rel') <= 5))
							{
								showResults(0);
							}
							else if(($(this).get('rel') >= 6) && ($(this).get('rel') <= 18))
							{
								showResults(1);
							}
							else if(($(this).get('rel') >= 19) && ($(this).get('rel') <= 25))
							{
								showResults(2);
							}
							else if(($(this).get('rel') >= 26) && ($(this).get('rel') <= 32))
							{
								showResults(3);
							}
							else if(($(this).get('rel') >= 33) && ($(this).get('rel') <= 36))
							{
								showResults(4);
							}
							else
							{
								showResults(0);
							}
						}
					}).send('section=' + $(this).get('section') + '&i=' + $(this).get('rel') + '&content=' + $(this).get('text'));
				});
			}
		});
	});

 

A JS error is given in IE8, "Object doesnt support this property or method". Its  line number is wrong though as it there is no JS on that line.

I get no error in firefox but it does not work.

 

Please have a look and tell me where I am going wrong.

Thanks in advance!

Link to comment
Share on other sites

I notice your using an id as the selector for results.  There is only one element with the id=results correct? As they can not be duplicated.  I could throw together a version of what you want in jQuery if you think that would help.

 

Yes, I have a div (id=results) which holds a table with <td class="editable"> in it. I would be most greatful if you could have a go because I am pulling my hair out with it.

Link to comment
Share on other sites

Ok heres a really quick example.  would have been easier with your html but should work.

$(document).ready(function(){
$('#results').click(function(e){
  if($(e.target).is('td.editable')){
    if($(e.target).hasClass('textarea')){
      $(e.target).html('<textarea class="box">'+$(e.target).text()+'</textarea>');
    }else{
      $(e.target).html('<input type="text" class="box" value="'+$(e.target).text()+'" />');
    }
    
    $(e.target).find('.box').keypress(function(k){
      if(k.which == 13){
        var data = $(this).val();
        $(this).parent().text(data);
        
        /// save your data or whatever else.
      }
    });
  }

});
});

Link to comment
Share on other sites

Ok heres a really quick example.  would have been easier with your html but should work.

$(document).ready(function(){
$('#results').click(function(e){
  if($(e.target).is('td.editable')){
    if($(e.target).hasClass('textarea')){
      $(e.target).html('<textarea class="box">'+$(e.target).text()+'</textarea>');
    }else{
      $(e.target).html('<input type="text" class="box" value="'+$(e.target).text()+'" />');
    }
    
    $(e.target).find('.box').keypress(function(k){
      if(k.which == 13){
        var data = $(this).val();
        $(this).parent().text(data);
        
        /// save your data or whatever else.
      }
    });
  }

});
});

 

Thanks a million JustLikeIcarus!

 

I adapted and extended your code to suit my needs, thanks a bunch!!!

 

One last question (I swear),

You will see from my code below that on blur the data is saved.

$(document).ready(function(){ 
		$('#results').click(function(e){  
			if($(e.target).is('td.editable')){    
				if($(e.target).hasClass('textarea')){      
					$(e.target).html('<textarea class="box">'+$(e.target).text()+'</textarea>');    
				}else{      
					$(e.target).html('<input type="text" class="box" value="'+$(e.target).text()+'" />');
				}
				$(e.target).find('.box').select();

				$(e.target).find('.box').blur(function(){             
					var data1 = $(this).val();        
					$(this).parent().text(data1);

						$.get("sessionupdater.php", 
							{ section: $(e.target).attr("section"), i: $(e.target).attr("rel"), content: data1 }, 
								function(data) { 

									if (($(e.target).attr("rel") <= 5))
									{
										showResults(0);
									}
									else if(($(e.target).attr("rel") >= 6) && ($(e.target).attr("rel") <= 18))
									{
										showResults(1);
									}
									else if(($(e.target).attr("rel") >= 19) && ($(e.target).attr("rel") <= 25))
									{
										showResults(2);
									}
									else if(($(e.target).attr("rel") >= 26) && ($(e.target).attr("rel") <= 32))
									{
										showResults(3);
									}
									else if(($(e.target).attr("rel") >= 33) && ($(e.target).attr("rel") <= 36))
									{
										showResults(4);
									}
									else
									{
										showResults(0);
									}

								} 
						);
				});

			}});});

I also want it to be when a user hits enter. I saw from you example you use k.which == 13 method.

 

I tried to use the following so that when a user hits enter it fill fire the blur event and save my data .But it does not work, I have but it before the blur event and after it but to no avail. This is the last bit I need to do, please help me.

 

$(e.target).find('.box').bind('keypress', function(e) {
if(e.keyCode==13){                
	$(e.target).find('.box').fireEvent('blur');
}
});

 

Link to comment
Share on other sites

Try it this way.. Also you can help yourself out alot by inserting alert()'s in places where you cant tell if something is firing right. making it alert to let you know it atleast got that far.

 

Since you bound the event to something when it occurs "this" is the element that invoked it.

$(e.target).find('.box').bind('keypress', function(e) {
   if(e.keyCode==13){               
      $(this).blur();
   }
});

Link to comment
Share on other sites

Try it this way.. Also you can help yourself out alot by inserting alert()'s in places where you cant tell if something is firing right. making it alert to let you know it atleast got that far.

 

Since you bound the event to something when it occurs "this" is the element that invoked it.

$(e.target).find('.box').bind('keypress', function(e) {
   if(e.keyCode==13){               
      $(this).blur();
   }
});

 

Absolutely spot on.

Thanks very much for your help. I'd be completely lost without this forum and the help I got from you.

 

Cheers,

briandaly40

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.