Laravel Tagging: Bootstrap Tags Input + rtconner

3 min read

Rob Conner has put together a great tagging class for Laravel. However it does not come with any client side scripting.

This post briefly explains how to use Tim Schlechter’s Bootstrap Tags Input with Connor’s TaggableTrait script for a total solution.

Step 1: Install laravel-tagging script into your Laravel Project

The instructions are here: https://github.com/rtconner/laravel-tagging
Be sure to include this into the class of the object that you will tag.

class myObject extends \Eloquent {
    use Conner\Tagging\TaggableTrait;
}

Step 2: Add jQuery & Bootstrap Scripts and CSS

1. Place CSS in the header:

<link rel="stylesheet" href="assets/bootstrap-2.3.2/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/bootstrap-tagsinput.css">

2. Place scripts at the bottom of the page:

<script src="assets/jquery.min.js"></script> 
<script src="assets/bootstrap-2.3.2/js/bootstrap.min.js"></script>
<script src="assets/bootstrap-tagsinput.js"></script>

Step 3: Create a Laravel function that will output the requisite tags input element

I put this function in my own Tools class along with my other custom functions. It will get called by the page view.

class Tools extends \BaseController  {

    public static function outputTags($tags){
	$tagfield = '<input type="text" value="';
	$tagfield .= implode(",", $tags);
	$tagfield .= '" data-role="tagsinput" placeholder="Add tags.." data-role="tagsinput"  />';
	echo $tagfield;
    }
}

This will take the tags list created by rtconner and reformat it to an input element that can be used by the bootstrap script.

The Bootstrap script can accept various formats of input – this generates the most simple form which looks like this:

<input type="text" value="Amsterdam,Washington,Sydney,Beijing,Cairo" data-role="tagsinput" />

Step 4: Include the outputTags function into your page view

Note that the $myobject is the object that is tagged and tagNames() gets the array of related tag names .

{{Tools::outputTags($myobject->tagNames());}}

Remember the tagNames() function will only work if TaggableTrait has been added to the object’s class per Step 1.

Step 5: Create an AJAX script to be triggered when the tags are updated

1. Put the object identifier where you will find it.
You will need to pass the id of the object that is being tagged. Do this by putting the id somewhere in the page and grabbing the value in the jQuery. Technically you could echo the id directly into the script using Eloquent (or PHP) but this is not very clean.

<input type="hidden" id="myobjectid" value="{{ @$myobject->id }}">

2. Create the script that will fire when tags are changed
Note that the Bootstrap tagging script has created some events which will only fire when the relevant input item is updated. So there is no need for any kind of id on the input element other than data-role=”tagsinput” already included above.

You will need to include your own path to the function which will process the tag (typically ‘myobject/myfunction’).

$(document).ready(function(){

	$('input').on('itemAdded', function(e) {
		tags =  $(this).val();
		updateTags(tags); 
	});

	$('input').on('itemRemoved', function(e) { 
		tags =  $(this).val();
		updateTags(tags); 
	});


    function updateTags(tags){
	url = '/myobject/editTags';
	id = $("#myobjectid").val();

	var posting = $.post (url, {tagData: tags, id: id} );

	posting.done(function( data ) {

		if(data.success) {
	  	    msg = 'Tag updated';
		} else {
		    msg = 'Sorry - the tag amendment was unsuccessful.';
		}
         
         alert(msg);

	});
    }

});

^^ This should go at the bottom of the page after the linked scripts.

Step 5: Create the data processing function in routes.php

Ajax calls do not generate views therefore the input will get processed directly in the routes.php class.
 

Route::post('myobject/editTags', function(){
		$newTags  = Input::get('tagData');
		$id = Input::get('id');
		$myobject = MyObject::findOrFail($id);
		$myobject->retag($newTags);

	 	return Response::json(array(
	    	'success' => true
	    ));

});