AdvancedCustomFields / acf

Advanced Custom Fields
http://advancedcustomfields.com/
871 stars 182 forks source link

model.setValue() does not trigger HTML re-render. Is it a bug? #137

Open wujekbogdan opened 5 years ago

wujekbogdan commented 5 years ago

I'm refactoring some piece of some old code where I use DOM traversing to change field's values programmatically. It works, however, I would prefer to use more elegant techniques if possible. I got excited a little that ACF has a new JS API, so I wanted to use it. I found there's a model.setValue() method, but It doesn't do what I expected it to do. ACF models look similar to Backbone models so I assumed that a change on the model will trigger HTML re-render, but it is not happening.

Is it a bug? Do I need to do anything else in order to get HTML re-rendered after calling model.setValue()? Or maybe model.setValue() is not supposed to be used this way and I still have to use good, old DOM traversing and update the HTML on my own?

elliotcondon commented 5 years ago

Hi @wujekbogdan

The Field.val() and Field.setValue() functions are simple, int that they only modify the $input element value. They won't act like a React component and re-render the field, sorry.

wujekbogdan commented 5 years ago

@elliotcondon So there's no official way to force field's HTML re-render. I have to do it on my own as I used to do so far. Right?


Here's an example, It's a handler that's executed after EXIF data is read from the image field. The handler loops through all the taxonomy checkboxes and selected these ones that match EXIF tags. Then it updated the HTML:

// Handle AJAX response
setTags(response) {
    if (!response.data.hasOwnProperty('keywords')) {
        return;
    }

    // Convert all tags to lowercase and trim.
    const normalize = (str) => str.toLowerCase().trim();
    const keywords = response.data.keywords.map((keyword) => {
        return normalize(keyword);
    });

    // Find all <li> elements
    const $li = fields.tags.$el.find('li');

    // Loop through al <li> elements and update checkboxes values based on tags
    $li.each((index, item) => {
        const $item = $(item);
        const text = normalize($item.text());
        const checked = keywords.indexOf(text) !== -1;

        $item.find('input:checkbox').attr('checked', checked);
    });
},
elliotcondon commented 5 years ago

@wujekbogdan Correct. We haven't yet implemented JS templating (such as React), so the Field.val() function won't update the UI. I'm very interested in moving towards a JS rendering engine in the future, but we are using PHP at the moment.

wujekbogdan commented 5 years ago

@elliotcondon Thanks. I'm closing the ticket then.