Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACF Field JavaScript API #38

Open
elliotcondon opened this issue May 7, 2018 · 2 comments
Open

ACF Field JavaScript API #38

elliotcondon opened this issue May 7, 2018 · 2 comments

Comments

@elliotcondon
Copy link
Contributor

elliotcondon commented May 7, 2018

Dear ACF and JS developers,

Work on our upcoming version 5.7 is now entering it's final stages! If you are not yet up to speed on the new changes, please read our ACF PRO 5.7.0 – New Architecture for New Features blog post.

Whilst we tidy up the remaining bugs, testing, beta releases and documentation, we would love to get your opinions, feedback and help in reviewing our JS library.

At the center of this library is the acf.Field class. This is what will be used the most by conditional logic, 3rd party developers and other core logic when interacting with a field.

Example

For example, you can find a field on the screen like so:
var field = acf.getField('field_123456');

You can then get it's value like so:
var val = field.val();

This is all pretty basic stuff, but each field type requires different logic due to it's unique Markup and functionality. What we have tried to do is break down these actions into easy to customize functions allowing for rapid development.

Breaking down .val()

For example, the val() function is broken down into getValue() and setValue() depending on if a value parameter is defined.

These functions call getInput() to find the field's "jQuery input element" and return it's jQuery .val().

This means that when creating the Select field type, all we needed to do for all conditional logic support was define the getInput() function to look like this:

var Field = acf.Field.extend({
	type: 'select',
	getInput: function(){
		return this.$('select');
	},
	// ...
});

acf.registerFieldType( Field );

The BIG question

We are quite happy with the acf.Field class in terms of its usability and functionality, but are still not 100% sure we nailed the naming conventions.

For now, lets focus on the getInput() function, but keep in mind that each field has other elements too which need to be 'standardized'. This includes the:

  • Label wrap: "> .acf-label"
  • Input wrap: "> .acf-input"
  • input control: ".acf-repeater:first" or ".acf-date-picker"

To help decide, we have put together some choices. Each have their own pros and cons. We have tested them all, and the performance between them are almost the same, so we are more interested in "what is the current standard" or "what is best for our developers".

Idea 1. Store on initialization

Each field is initialized once (either on page load or when the HTML is newly appended). This is used to initialize field specific functionality such as .sortable() or .datepicker().

During initialization, we currently set the field jQuery object to the field.$el property. It would be easy enough to also set the $input, $control and any other $elements.

The field object would then look like so:

var field = {
	$el: jQueryElement,
	$input: jQueryElement,
	$control: jQueryElement,
	// ...
}

The upside to this, is that all jQuery elements are distinctly found with the prefix '$' which would help "console log debugging". For example, field.search = function(){}; and field.$search = jQueryElement;

The downside is this will add unnecessary "jQuery searching" during initialization to find elements.

Idea 2. Stick with getElement

As we currently have it, elements are found using get prefixed functions.

The field object looks like so:

var field = {
	$el: jQueryElement,
	getInput: function(){ return jQueryElement;  },
	getControl: function(){ return jQueryElement;  },
	// ...
}

The upside of this is that during initialization, there is no unnecessary "jQuery searching".
The downside is that without documentation, it is not clear these functions return jQuery elements.
For example, field.getValue() returns the field's value, but and field.getInput() returns a jQuery element.

Idea 3. A mixture of both

We have also tried a version that mixes both ideas together and looks like so:

var field = {
	$el: jQueryElement,
	$input: function( return jQueryElement; ),
	$control: function( return jQueryElement; ),
	// ...
}

The upside of this is that these functions are easy to identify as jQuery element functions. You would use them like so:
field.$control().addClass('has-value');

Idea 4. Find

Throughout the new JS library, we have used the prefix "find" when returning jQuery elements, and "get" when returning native JS types. For example:

// returns a collection of jQuery field elements
var $fields = acf.findFields();

// returns an array of `acf.Field` instances.
var fields = acf.getFields();

Following in these footsteps we could use the same principles like so:

var field = {
   $el: jQueryElement,
   findInput: function(){ return jQueryElement;  },
   findControl: function(){ return jQueryElement; },
   // ...
}

The upside to this is a much more coherent JS library.

How to contribute

Please leave your comments below, we would love to hear from you. Please remember to be diplomatic and helpful in our conversation. Everyone is entitled to their own opinion, and we are looking for positive ideas, suggestions and feedback.

Thanks
Elliot

@tarikhamilton
Copy link

If I am understanding this correctly, #2 getInput(), getControl() also return jQuery elements, correct? If the are, the examples are a little inconsistent, which is what threw me off. If that is the case, I like idea #3 because you know they're jQuery and it seems more performant to only query when necessary, however you said performance is negligible.

But I also feel like I'm missing something. What is something like field.search = function(){}; supposed to return in #1?

When you say return a JS type instead of jQuery element, is there a JS object representing a field or do you mean returning an HTML${n}Element?

@elliotcondon
Copy link
Contributor Author

elliotcondon commented May 9, 2018

Hi @tikitariki

Thanks for the reply and feedback. You raised some great points, and I'll address them below:

Point 1

If I am understanding this correctly, #2 getInput(), getControl() also return jQuery elements, correct?

Yes. I've just updated the examples to better reflect this.

Point 2

I like idea #3 because you know they're jQuery and it seems more performant to only query when necessary, however you said performance is negligible.

I'm leaning towards this idea too. It optimizes performance by only querying when needed, but also allows these functions to become dynamic and even allow for parameters.

Point 3

What is something like field.search = function(){}; supposed to return in #1?

This was an example to demonstrate how naming conventions are important. All functions that start with a $ symbolize those that return a jQuery element, nothing else.

Point 4

When you say return a JS type instead of jQuery element, is there a JS object representing a field or do you mean returning an HTML${n}Element?

Here I am talking about the differentiation between a jQuery object and any other JS type. The getX functions should return a JS type (string, int, object, array, etc) where as the findX functions should return a jQuery object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants