Question

I have code that dynamically creates a product features list and puts all the values together into one string seperated by newline characters and gets saved to the database. When this string is passed to the view I output as an unordered list. When I go to edit the block it does not show what is already in the list, so I have to retype all the features everytime I need to edit my block, even if it's not the feature list (I have some titles and other textareas). If I put the php variable into my edit page it will show me what has been saved but I would need it to be instantly added to the list and not showing separate. I basically need it to "auto appendTo" my <ul>. Here is my code...

controller function to save the list in controller.php

public function save($args) {
        $args['features'] = implode("\n", $args['features']);//combine all feature items into one string, separated by "newline" characters
        parent::save($args);
    }

my edit.php - this will show it in a list. If I just put echo $features it outputs the string.

echo '<div class="ccm-block-field-group">';
echo '<h2>' . t('Features') . '</h2>';
echo '<input type="text" id="inputList" />';
echo '<button type="button" id="addList">Add</button>';
echo $features = explode("\n", $features);
        foreach ($features as $feature) {
            echo '<li class="currentFeatures">' . $feature . '</li>';
        };

echo '<ul class="featureList">';
echo '</ul>';
echo '</div>';

my auto.js - handles creation of the list

var listItemCounter = 0;
    $("#addList").click(function() {
        listItemCounter++;
        var text = $("#inputList").val(); //assign a unique id number to this button, so it knows which hidden field to remove when clicked
        var buttonDataId = text + '<button data-id="' + listItemCounter + '">x</button>';
        if(text.length){
            $('<li />', {html: buttonDataId}).appendTo('ul.featureList');
            $('<input type="hidden" name="features[]" value="' + text + '" data-id="' + listItemCounter + '" />').insertAfter('ul.featureList');
            };
    });
    $('ul').on('click','button', function(el){
        $('input[data-id="' + $(this).attr('data-id') + '"]').remove();//remove the hidden field so it does not get POSTed when user saves
        $(this).parent().remove()
    });

and finally part of my db.xml

<field name="features" type="X2"></field>
Was it helpful?

Solution

You'll want to do something similar to what I explained for the "view" in your other question ( https://stackoverflow.com/a/14968046/477513 ).

You want to change the list from a string to an array (via explode("\n", $features)), then run your javascript on each of those features. Since this is basically the same javascript that you'd do when someone adds a new item via the textbox, you will want to move all that code into a function and call the function in both situations (otherwise you will be copying and pasting the same code, which violates the "Don't Repeat Yourself" rule and inevitably leads to bugs in the future). So your auto.js code could look something like this:

var listItemCounter = 0;

function addItem(text) {
    if (text.length) {
        listItemCounter++;
        var itemHtml = '<li data-id="' + listItemCounter + '">'
                     + text
                     + '<button data-id="' + listItemCounter + '">x</button>'
                     + '</li>';
        var inputHtml = '<input type="hidden" name="features[]" value="' + text + '" data-id="' + listItemCounter + '" />';
        $('ul.featureList').append(itemHtml);
        $('ul.featureList').after(inputHtml);
    }
}

function removeItem(id) {
    $('input[data-id="' + id + '"]').remove();
    $('li[data-id="' + id + '"]').remove();
}

$("#addList").click(function() {
    additem($("#inputList").val());
});

$('ul').on('click','button', function(el) {
    var id = $(this).attr('data-id');
    removeItem(id);
});

Then in your edit.php file, add this code to output the saved data and call the addItem function on each one:

<?php
//populate existing data when edit dialog is first opened
$featuresPHPArray = explode("\n", $features);
$featuresJSArray = Loader::helper('json')->encode($featuresPHPArray);
?>
<script>
var savedItems = <?php echo $featuresJSArray; ?>;
$.each(savedItems, function() {
    addItem(this);
});
</script>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top