Extend Yii with TAG IT! (a jquery plugin)

Hi all! I need a plugin like this TAG IT!. Yii dont support natively this stuff. What I’ve to for adding this stuff in my Yii and keep clean the code?

I used http://www.yiiframework.com/extension/taggable, together with http://www.yiiframework.com/extension/tag-widget to do exactly that

I’ve some trouble with taggable behavior. I’ve tried to download 1.4 but there is something wrog. Zip file contains /yiiext/behaviors/model/taggable/yiiext/behaviors/model/taggable path. I think it is no normal. I think this really means “/yiiext/behaviors/model/taggable” and not all the entire path. Well … I try to install it

I tried to install this in my config


return array(

  // ...

  'import'=>array(

        'application.models.*',

        'application.components.*',

        'ext.yiiext.behaviors.model.taggable.*',

        // ...

        // other imports

    ),

    // ...

);

ok

after that I’d tried to alter my model Class:


  public function behaviors() {

    return array(

        ...

        'tags_with_model' => array(

            'class' => 'ext.yiiext.behaviors.model.taggable.EARTaggableBehavior',

            // tag table name

            'tagTable' => 'Tag',

            // tag model class

            'tagModel' => 'Tag',

        ) // tags_with_model

        ...

    );

  }

And then?

I think guide is not clear!

I forgot onw thing: now I’ve a “News” table that I need to make taggable.

Hi,

What I did is:

created a table tbl_tag (id, name, frequency)

created a table tbl_news_tag (newsId, tagId)

(you set up your news table as you wish (same as your tag and news_tag tables, i normally use a table prefix)

put the extension into protected/behaviors/model/

change my config to import the classes of the extension




// autoloading model and component classes

	'import'=>array(

		// ..

		'application.behaviors.model.taggable.*'

	),



add the behavior to my news model class




public function behaviors(){

		return array(

			'tags_with_model' => array(

				'class'=>'application.behaviors.model.taggable.ETaggableBehavior',

				'tagTable'=>'tbl_tag',

				'tagBindingTable' => 'tbl_news_tag',

				'modelTableFk' => 'newsId',

				'tagTablePk' => 'id',

				'tagTableCount' => 'frequency',

				'tagBindingTableTagId' => 'tagId',

				'createTagsAutomatically' => true,

			)

		);

		

	}



done…

Next steps

create a Tag Model and TagController

create an action on your TagController that receives the calls of autocomplete Tag Widget




// on the News Form

<div class="row">


		<?php $this->widget('application.widgets.tag.TagWidget', array(

            'url'=> $this->createUrl('tag/json'),

            'tags' => $model->getTags()

        ));

        ?>

	</div>

// on the TagController json action

public function actionJson(){

	    header('Cache-Control: no-cache, must-revalidate');

	    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

	    header('Content-type: application/json');

	 

	    $this->layout = false;

	    if(isset($_GET['tag'])){

	         

	        $criteria=new CDbCriteria(array(

	            'limit' => 10

	        ));

	         

	        $criteria->addSearchCondition('name', $_GET['tag']);

	 

	        $tags = Tag::model()->findAll($criteria);           

	 

	        $this->render('json', array('tags' => $tags));

	    }

	}



On the NewsController




/**

	 * Creates a new model.

	 * If creation is successful, the browser will be redirected to the 'view' page.

	 */

	public function actionCreate()

	{

		$model=new News;


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['News']))

		{

			$model->attributes=$_POST['News'];

			

			if(!isset($_POST['Tags']))

				$model->setTags('Unclassified');

			else

				$model->setTags($_POST['Tags']);

			

			if($model->save())

				$this->redirect(array('view','id'=>$model->id));

		}


		$this->render('create',array(

			'model'=>$model,

		));

	}


	/**

	 * Updates a particular model.

	 * If update is successful, the browser will be redirected to the 'view' page.

	 * @param integer $id the ID of the model to be updated

	 */

	public function actionUpdate($id)

	{

		$model=$this->loadModel($id);


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['News']))

		{

			$model->attributes=$_POST['News'];

			

			if(!isset($_POST['Tags']))

				$model->setTags('Unclassified');

			else

				$model->setTags($_POST['Tags']);

			

			if($model->save())

				$this->redirect(array('view','id'=>$model->id));

		}


		$this->render('update',array(

			'model'=>$model,

		));

	}



The information of the Tag Widget and Taggable Behavior are quite good and was easy to follow. Nevertheless, I truly hope my hints will help you to get to the right track.

Cheers

Very thank you. Now I’m using an home made system to do this. I’ll try your solution soon. I love code but I dont like coding in “non standard” ways.

For use newbies, could you indicate what might “non standard” coding above? I’m looking at using this and would like to learn the “right” way to do things :)

This is what I’ve done and what people DONT have to do =):

In form page, I show a textField that shows categories and I’ve an hidden field that contains ids of these categories. These is becaouse I want to keep translations of each categori. (with category i means tag). The idea is that if a category is not in the list, I permit users to add on the fly new category.




  <div class="row">

    <?php echo $form->labelEx($model, 'categorie'); ?>

    <?php echo $form->textField($model, 'categorie', array('size' => 60, 'maxlength' => 128, 'readonly' => 'readonly')); ?>

    <?php echo $form->hiddenField($model, 'idcategorie'); ?>

<?php echo $form->error($model, 'categorie'); ?>




    <table width="100%">

      <tr>

        <td><div id="elenco_tagg"></div><?php

$this->beginWidget('zii.widgets.jui.CJuiDialog', array(

    'id' => 'mydialog',

    'options' => array(

        'title' => 'Add new Tag',

        'autoOpen' => false,

        'modal' => true,

    ),

));


$this->renderPartial('/site/pages/addTag');

$this->endWidget('zii.widgets.jui.CJuiDialog');


echo '(' . CHtml::link('add new tag', '#', array(

    'style' => 'color: darkred; text-decoration: none;',

    'onclick' => '$("#mydialog").dialog("open"); return false;',

)) . ')';

?></td>

      </tr>

    </table>


  </div>



The modal dialog, open this page:




<script>

  $.ajax({

    url: 'index.php?r=tagajax',

    success: function(data){

      $('#elenco_tag').html(data);

    }

  });

</script>

<div class="row">

  <label for="categoria_da_aggiungere">Categoria</label>

  <input type="text" id="categoria_da_aggiungere">

  <button onclick="

    var cat = $('#categoria_da_aggiungere').val();

    if(cat == '')

      alert('la categoria non può essere vuota!');

    else {


      $.ajax({

        type: 'POST',

        url: 'index.php?r=categorie/create',

        data: {'Categorie[nome]':cat,'ajax':true},

        success: function() {


          $('#categoria_da_aggiungere').val('');


          $.ajax({

            url: 'index.php?r=tagajax/index',

            success: function(data){

              $('#elenco_tag').html(data);


              $.ajax({

                url: 'index.php?r=tagajax/link',

                success: function(data){

                  $('#elenco_tagg').html(data);

                }

              });


            }

          });


        }

      });





    }

          ">Aggiungi</button>

</div>

<div id="elenco_tag">

</div>



Notes that the list of tags in the form is a new controller:




<?php


class TagajaxController extends Controller {


  public function actionLink() {


    $m = Categorie::model()->findAll();

    $contatore = count($m);


    foreach ($m as $item) {

      echo '<a href="javascript:return false;" style="text-decoration: none;" onclick="


        /* aggiungo un elemento al JSON */

        if(provami[\'' . (addslashes(strtolower($item['nome']))) . '\'] != null) {

          delete provami[\'' . (addslashes(strtolower($item['nome']))) . '\'];

          delete idtags[\'' . (addslashes(strtolower($item['nome']))) . '\'];

        } else {

          provami[\'' . (addslashes(strtolower($item['nome']))) . '\'] = \'' . (addslashes(Yii::t('categorie',$item['id']))) . '\';

          idtags[\'' . (addslashes(strtolower($item['nome']))) . '\'] =  '. ($item['id']) . ';

        }


        /* Creo la stringa dal CSV per la textbox */

        tags = \'\';i=0;

        for(ii in provami) {

          tags += (++i==1?\'\':\',\') + provami[ii];

        }


        /* Creo la stringa dal CSV per il campo hidden */

        tagsid = \'\';i=0;

        for(ii in idtags) {

          tagsid += (++i==1?\'\':\',\') + idtags[ii];

        }


        /* Ricopio il JSON dentro il campo di testo */

        $(\'#News_categorie\').val(tags);

        $(\'#News_idcategorie\').val(tagsid);


        ">' . (strtolower(Yii::t('categorie',$item['id']))) . '</a>' . (--$contatore ? ', ' : '. ');

    }

  }


  public function actionIndex() {

    ?>


    <?php $m = Categorie::model()->findAll(); ?>

    <ul>

      <?php foreach ($m as $item): ?>

        <li><?php echo Yii::t('categorie',$item['id']); ?></li>

      <?php endforeach; ?>

    </ul>


    <?php

  }


}



Also note that when you add a category in the modal dialog, this will appear in modal list and also in form page. I like this! Is 2.0!!! But Its also the worst way to code.

I need this solution, but I hope to learn a better way to code this.

Are you afraid =) ?

Not that I’m aware of :o , but that could be because I don’t know enough ::)

Hi, i just followed Antonio Ramirez´s instructions but have a problem.

I am using the modified version of Yii tag it from Sam Dark.

The first missing information is to create a json.php in views/tag that delivers the tags from the database.

An example can be found at h t t p://con.cept.me/blog/post/2/yii-tag-it-widget.

But I had to modify it, since i have no $tag->slug.


[<?php if($tags){

$total = count($tags) - 1;

foreach ($tags as $i =>$tag){

    //echo $tag->name;

    echo '{';

    echo '"id": "'.$tag->id.'",';

    echo '"label": "'.$tag->name.'",';

    echo '"value": "'.$tag->name.'"';

    echo '}';

    if($total !== $i){

        echo ',';

    }

}


}?>]

After that I had to add "json" to the accessRules in TagController.

in the form file "_form.php" i had to implode the tags:


<div class="row">


                <?php $this->widget('application.components.widgets.tag.TagWidget', array(

            'url'=> $this->createUrl('tag/json'),

            'tags' => implode(',',$model->getTags()),

	    //'tags' => $model->getTags(),

        ));

        ?>

        </div>

Now on to my problem. When I create a new article (or news) in my tags field an empty tag appears. If I add more tags they get added to the field. But when I save my entry for the first time the tags field reads "unclassified" and all other tags are lost. Same if I delete the empty tag first and add my tags afterwards.

Now I "update" the entry and add my tags, delete the tag named "unclassified" and everything works fine. Anyone else got this problem or knows a workaround?

Taggable is an awesome addition to Yii. But I still have one, probably silly question:

I have installed both the Taggable behavior and the widget, but I can’t figure out how to make an index page with all posts belonging to a chosen tag, resulting in a ‘standard’ Yii view. I just can’t get the $criteria in the actionIndex right.

Could you please point me in the right direction? Or is this not the right way to go, anyway? Many thanks in advance!

I also want to know this

I do something like this:


	public function actionIndex($tag = null) {

    	if (null != $tag) {

        	$posts = Post::model()->taggedWith($tag)->findAll($criteria);

    	} else {

        	$posts = Post::model()->findAll($criteria);

    	}


    	$this->render('index', array(

        	'model' => $posts,

    	));

	}



Where do I have to do this? In the model? Sorry, I am very new to this whole MVC thing.

That’s the index action of my PostController :)

i’ve implemented Taggable and Tag It! and for the most part its working - however, no list of suggestions is popping up in my view. I’ve checked the JSON response in Firebug and its an array of tags, so theoretically it should be working. Why would the list of suggestions not appear?

Hi, I have done this too, exactly the same. The thing is that everything seems to work fine, I write a letter, a little dropdown shows with the suggested matching words an when I press down key for select one, the dropdown disappears. It also do it when I try it clicking or even when I pass the mouse over the dropdown. What may be doing this? :c

I’ve got this working thanks to many of these posts, especially Aceman3000 who put me on the trail of creating a json.php. However, using that, as specified by Aceman, gives me a dropdown with three lines for each potential match as you might expect from his code which specifies that id, label, and value be echoed.


[<?php if($tags){

$total = count($tags) - 1;

foreach ($tags as $i =>$tag){

    //echo $tag->name;

    echo '{';

    echo '"id": "'.$tag->id.'",';

    echo '"label": "'.$tag->name.'",';

    echo '"value": "'.$tag->name.'"';

    echo '}';

    if($total !== $i){

        echo ',';

    }

}


}?>]

What I’d like to do is display just the label much like more traditional, HTML-generated dropdowns with the id and value hidden behind it. Unfortunately, my jQuery/JavaScript skills are about zilch. Can anyone help me with how to achieve that?