I’m trying to add a repeater row on a front-end form using Javascript. Can I programmatically trigger the same event that happens with the “Add row” button that typically appears under the repeater field?
Yes
$('[data-key="field_0123456"] .acf-input .acf-actions [data-event="add-row"]').trigger('click');
field_0123456 represents the field key of your repeater
edit: to correct typo from corrected in next comment
Hello
Not working
Fixed with :
$(‘[data-key=”field_0123456″] .acf-input .acf-actions [data-event=”add-row”]’).trigger(‘click’);
Thank you
Is there an event that can be detected when a new row is added?
I’d like to listen for when the new row is added, and then do something after that (like put up a prompt to guide the user along, etc.)
I think I have part of it figured out, but I have reached the limits of what I know about with jQuery. I have a repeater row set up with various inputs, including a WYSIWYG editor. I would like to add a copy/paste button so I can just duplicate that row’s contents, or even go to another Post and paste a row.
So far, I have figured out how to add a copy button, and how to add a paste button (which basically creates a row).
Here is what I have so far; can someone review and help me figure out how to access each of the fields in a repeater row via Javascript?
// first make some buttons that we are adding dynamically:
var acf_paste_button = '<a class="acf-button button" id="acf_paste_row" href="#" data-event="paste-row">Paste Row</a>';
// TODO: Give the copy button a FA of acf-font icon
var acf_copy_button = '<a class="small acf_copy_row" href="#" data-event="copy-row" title="Click to copy this row">C</a>';
// global: Keep track of button-pasted state:
var acf_button_pasted = false;
// add a button to the bottom of the actions area:
$('.acf-actions').prepend(acf_paste_button);
// add some copy buttons to each row in the ACF:
$('td.acf-row-handle').append(acf_copy_button)
//when you click the paste row button, send a click to the "add row" button
$('body').on('click','#acf_paste_row', function() {
$('.acf-button.button.button-primary').click();
acf_button_pasted = true;
});
// when you click the coyp row, put it into a cookie
$('body').on('click','.acf_copy_row', function() {
alert('todo: COPY the inputs of this row into a cookie');
});
// listen for pasting events:
acf.add_action('append', function( $el ){
// $el will be equivalent to the new element being appended $('tr.row')
if ( acf_button_pasted ) {
// so we just added a row; now we need to add a copy button for it:
$el.find('td.acf-row-handle').append(acf_copy_button);
// find a specific field
console.log($el);
var $field = $el.find('#my-wrapper-id');
var $field = $el.find('.acf-row');
console.log($field);
console.log('now it is time to paste the stuff');
// set the flag back to false in case you want to paste again.
acf_button_pasted = false;
// .acf-input-wrap
// do something to $field
// TODO: Paste values into each of the inputs.
$el.find('input').val('fish');
// how to access a WYSIWYG editor?
//tinymce.activeEditor.execCommand('mceInsertContent', false, " <b>bolded text</b> ");
$('.tmce-active').execCommand('mceInsertContent', false, " <b>bolded text</b> ");
// TODO: run through each element
$el.each( 'input', function(el) {
console.log(el);
});
}
});
There is a built in action that triggers when a row is added, see “Append” https://www.advancedcustomfields.com/resources/adding-custom-javascript-fields/
HI John,
That is great, but now how do I loop through the ACF input/textarea fields within that row? In the example:
acf.add_action('append', function( $el ){
// $el will be equivalent to the new element being appended $('tr.row')
// find a specific field
var $field = $el.find('#my-wrapper-id');
// do something to $field
});
I do not understand the $el.find(‘#my-wrapper-id’);. I do not know what the ID of this new row is.
I was trying to do $el.each(‘input’) or something like that and couldn’t get this to work.
After a second or whatever, then newly-created row seems to have an ID of sizzle1529351842030 and when you create another row, the previous sizzle-row loses its ID, and so on. Where does the “sizzle” get its numeric portion (1529351842030)? Is that related to the ACF internal ID or is it just a timestamp?
So what I would like is a way to access all of the ACF inputs/text areas, buttons, selects, on that new row, as I want to populate it dynamically. Also, I am unsure how to set the contents of an ACF wysiwyg (tinymce) field.
#my-wrapper-id represents the ID you set for the field when creating it under the “Wrapper Attributes” settings.
I think by looking at your code you know that $el.find...
would find nested elements inside of the new row, but you can target many things.
You don’t need to use your ID, you could use any of the values output by ACF.
for some examples:
// get all of the acf field elements (TDs or DIVs) in the added row
$fields = $el.find('.acf-field');
// get all of the input elements in added row (i.e. <div class="acf-input ....
$fields = $el.find('.acf-input');
// get all of the textarea input fields
$fields= $el.find('div[data-type=textarea"]');
// get a specific textarea field in the row
// field_123456 represents the field key of the field
$field = $el.find['[data-key="field_123456"] .acf-input textarea'];
Loop over elements
// your could loop over each field like this
var $fields = $el.find('.acf-field').each(function(index, element) {
var $key = $(element).data('key');
switch ($key) {
case 'field_1234456':
// do something
break;
case 'field_654321':
// do something else
break;
} // end switch
});
you can go directly to the field with additional “find(s)”, but eventually you’ll need to know the field key for the ACF field, or some other specific information in order to get the value or set it, for example #my-wrapper-id
given in the example.
WYSIWYG fields are a special case. Not only do you need to target the acf field but you also need to target the tinyMCE element of that field and use tinyMCE methods to get or set the value. Tiny MCE keeps a list of all of the editors in the tinyMCE.editors
object. Each element of this object as an ID, for example tinyMCE.editors[index].id
. This ID value matches the ID value of the ACF field, which is dynamically generated for this purpose, so the only way to use it is to get it from the field. For example, in a test WYSIWYG field I just looked at the ACF field textarea looks like this
<textarea id="acf-editor-5b282e0b20cfc" class="wp-editor-area" name="acf[field_5b282dbecfe9e]" style="height:300px;"></textarea>
That ID is the ID of the editor value of the editor. You loop through this list of editors to find the one you want.
var $id = $('[data-key="field_123456"] .acf-input textarea).attr(id);
$editor = false;
for (i=0; i<tinyMCE.editors.length; i++) {
if ($id == tinyMCE.editors[i].id) {
// found the right one, set and stop
$editor = tinyMCE.editors[i];
break;
}
}
if ($editor) {
// this is a tinyMCE function call
$editor.setContent("some value");
}
I’ve probably given you more questions than answers in all this information. Custom JavaScript for ACF can be quite complex and there is very little documentation and what is there is pretty basic. We are mostly on our own in this area. The only reason I have any idea is by doing a lot of experimenting and looking a lot of HTML that is created by ACF.
Hmm, the wysiwyg editor is really hard to grab. To your code I’ve added the following, as the above method of getting the ID of the wysiwyg did not work, and apparently, when the wysiwyg is there, the textarea is not (and vice-versa):
var $fields = $el.find('.acf-field').each(function(index, element) {
console.log('---');
var $type = $(element).data('type');
if ($type == 'group') {return;}
console.log('type:' + $type);
var $key = $(element).data('key');
var $val = $('input[name*=' +$key ).val();
if ($type == 'wysiwyg') {
console.log('looking for wysiwyg');
// does not work:
// var $id = $('[data-key="' + $key + '"].acf-input textarea').attr('id');
var $id = $(element).find('.acf-input div').attr('id');
//something similar; we have to trim the -wrap suffic and the wp- prefix:
$id = $id.replace('-wrap','');
$id = $id.replace('wp-acf','acf');
console.log('id' + $id);
$val = find_editor($id, 'get', '');
if ($val == undefined) {
console.log('no wysiwyg visible, look for textarea');
$val = $('#' + $id).val();
}
}
console.log($key);
console.log($val);
});
and then I added a function for get/set of the Tiny editor:
function find_editor($id, action, value) {
$editor = false;
for (i=0; i<tinyMCE.editors.length; i++) {
console.log(tinyMCE.editors[i].id);
if ($id == tinyMCE.editors[i].id) {
// found the right one, set and stop
$editor = tinyMCE.editors[i];
break;
}
}
console.log($editor);
if (action == 'set') {
if ($editor) {
// this is a tinyMCE function call
$editor.setContent("some value");
}
}
if (action == 'get') {
if ($editor) {
// this is a tinyMCE function call
return $editor.getContent();
}
}
}
So, this is beginning to work. I am not dealing with other inputs such as checkboxes yet.
The topic ‘Add new repeater row on front-end form with Javascript’ is closed to new replies.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.