Categories Selection
The user can select a category in 2 ways:
- Start typing the category, or
- Press the down arrow, which will provide a list of categories
Either way will produce the drop-down of categories as shown below:
There is code for the categories selection in:
The PHP Edit View:
<div class="input select" id="select_categories"> Categories<br> <ul class="item-list categories"> <?php // Loop through each category foreach ($categories AS $categoryId=>$categoryName) { // If this category is in the array of categories already associated with this post (in the categories_posts table), then set class=active to show the category. Otherwise the category stays hidden and isn't selected if (in_array($categoryId,$categoriesSelected)) { $selected = "class='active'"; } else { $selected = ""; } // Create each category in a list, but only display if class=active is set echo '<li item="' . $categoryId. '" title="' . $categoryName . '"' . $selected . '>' . $categoryName;; // Allow removal of an active category echo '<a class="close" title="Remove ' . $categoryName . '">x</a>'; echo '</li>'; } // This is an autocomplete input form, that displays available categories. You can also cursor down to display a list ?> <li class="input"><input class="item-input" value="" tabindex="2" placeholder="Start typing or press down"></li> </ul> </div>
The Javascript for the Edit View:
$(function() { // Enable a multi auto complete drop down box when selecting categories to apply blog post to $(".categories").multiautocomplete({formField: "#categories"}); });
And the Multi Auto Complete Javascript code:
$.widget("ui.verboseautocomplete", $.extend({}, $.ui.autocomplete.prototype, { _response: function(contents) { $.ui.autocomplete.prototype._response.apply(this, arguments); $(this.element).trigger("autocompletesearchcomplete", [contents]); //alert("response") } })); (function($) { //multiautocomplete is called upon loading the page from \admin\app\webroot\js\posts\edit.js $.fn.multiautocomplete = function(options) { var options = options || {}; options.formField = options.formField || ""; // itemList is binded to <ul class="item-list categories"> and we'll loop through each <li> var itemList = this; // Will hold all the categories var names = []; // Used to create the indexed array for the HABTM relation between a Post and its Categories var postCategoryCounter = 0; // This will hold all the selected categories to pass through the form var outArray = []; function setOutput(){ var categoryIdField; var postIdField; var postIdValue = document.getElementById("PostId").value; var x; // Find already selected (active) categories, and add to the outArray itemList.find("li.active").each(function(){ // Check if it already exists if(outArray.indexOf($(this).attr("item")) == -1) { outArray.push($(this).attr("item")); categoryIdField = '<input type="hidden" class="categories" name="data[Category][' + postCategoryCounter + '][id]" value="' + $(this).attr("item") + '">'; $("#select_categories").append(categoryIdField); postCategoryCounter++; } }); } // Add all the categories to the names array itemList.find("li").each(function(){ names.push({label:$(this).attr("title"), value:$(this).attr("item")}); }); itemList.find("a.close").click(function(){ var parentItem = $(this).parent(); var parentItemValue = parentItem.attr("item"); var v; var categoryValue; var index = outArray.indexOf(parentItemValue); // Remove the selected category from the active list displayed parentItem.slideUp('fast',function(){parentItem.removeClass('active');setOutput();}); // Remove category from the hidden categories class fields $.each($(".categories"), function(key, value) { // If the category looped over equals the category removed, then remove this categories hidden field categoryValue = $(".categories")[key].value; if (parentItemValue == categoryValue) { // Found hidden field with this categories value and remove $(this).remove(); // Also remove from the outArray, which allows us to add it back again. if (index > -1) { outArray.splice(index, 1); } } }); return false; }); // Just finding the input field within the item list var _InputField = itemList.find("input"); // Listen to any events on the input field _InputField.verboseautocomplete({ minLength: 0, source: names, select: function(event, ui){ var selectedItem = itemList.find("li[item="+ui.item.value+"]"); selectedItem.slideDown('fast',function(){selectedItem.addClass('active');setOutput();}); _InputField.val(''); return false; }, focus: function( event, ui ) { // Only works if the mouse is focusing on it, not the arrow keys $(".item-input").val(ui.item.label); } }).bind("autocompletesearchcomplete", function(event, contents) { if(contents.length == 0){ $(this).autocomplete("widget").html('<li><p class="ui-corner-all">No results found.</p></li>'); $(this).autocomplete("widget").show(); } }); setOutput(); } })(jQuery);
Where it is all saved in the Posts Controller Code
/* Form is being submitted. Save data */ if ($this->request->is(array('post', 'put'))) { $this->Post->id = $id; $saveStatus = $this->Post->save($this->request->data); if ($saveStatus ) { // Saving (associating) the categories selected for this post $this->loadModel('CategoriesPosts'); $this->CategoriesPosts->saveCategories($this->request->data["Category"], $this->Post->id); $this->Session->setFlash(__('Your post has been updated.')); return $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('Unable to update your post.')); }
Comments