Yii CGridView Spalte mit CLinkColumn verlinken

CLinkColumn erleichtert die Arbeit eine Zelle zu verlinken

Im Yii CGridView ist es relativ einfach eine Spalte zu verlinken. Nehmen wir mal als Beispiel an, es gibt eine Spalte in der Lieferanten aufgelistet werden sollen. Viele der Lieferanten besitzen eine Webseite und diese soll im CGridView so angezeigt werden, dass die Webseite direkt verlinkt ist. Yii bringt hierfür die Klasse CLinkColumn mit. Mit der Klasse CLinkColumn können wir eine Spalte direkt verlinken. Eingesetzt wird CLinkColumn wie in dem folgenden Beispiel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$this->widget('bootstrap.widgets.CGridView', array(
  'id'=>'kunden-grid',
  'dataProvider'=>$model->search(),
  'filter'=>$model,
  'summaryText'=>'',
  'columns'=>array(
    'id',
    array(
      'class'=>'LinkColumn',
      'header'=>'$data->firma',
      'labelExpression'=>'$data->firma',
      'urlExpression'=>'$data->website',
      'linkHtmlOptions'=>array('target'=>'_blank'),
    ),
    'strasse',
    'plz',
    'ort',
  ),
));

Wir sehen, dass wir also als Spalte ein Array angeben und diesem die Klasse CLinkColumnübergeben. Das ganze hat jedoch einen gravierenden Nachteil, der mir gar nicht gefällt. Ich kann hier keinen Namen einer Eigenschaft eines ActiveRecord übergeben. Dies stört mich aus dem einfachen Grund, dass es mit dem CLinkColumn nicht mehr so einfach wird, Filter-Optionen mitzugeben. Ich bekomme also nicht einfach ohne weiteres eine Filterzelle angezeigt. Außerdem möchte ich, dass die Spaltenbeschriftung genau mit dem ActiveRecord übereinstimmt. Ich habe hierzu eine eigene Klasse abgeleitet, die ich einfach unter “components” abgelegt habe. Die Klasse habe ich LinkColumn genannt und baut sich wie folgt auf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class LinkColumn extends CLinkColumn{
  public $filter;

  public $name = null;
  public $sortable=true;

  public function renderFilterCellContent(){
    if(is_string($this->filter))
      echo '<div class="filter-container">'.$this->filter.'</div>';
    else if($this->filter!==false && $this->grid->filter!==null && $this->name!==null && strpos($this->name,'.')===false)
    {
      if(is_array($this->filter))
        echo '<div class="filter-container">'.CHtml::activeDropDownList($this->grid->filter, $this->name, $this->filter, array('id'=>false,'prompt'=>'')).'</div>';
      else if($this->filter===null)
        echo '<div class="filter-container">'.CHtml::activeTextField($this->grid->filter, $this->name, array('id'=>false)).'</div>';
    }
    else
      parent::renderFilterCellContent();
  }

  public function renderHeaderCellContent(){
    if($this->grid->enableSorting && $this->sortable && $this->name!==null)
      echo $this->grid->dataProvider->getSort()->link($this->name,$this->header,array('class'=>'sort-link'));
    else if($this->name!==null && $this->header===null)
    {
      if($this->grid->dataProvider instanceof CActiveDataProvider)
        echo CHtml::encode($this->grid->dataProvider->model->getAttributeLabel($this->name));
      else
        echo CHtml::encode($this->name);
    }
    else
      parent::renderHeaderCellContent();
  }
}

Dies mag im ersten Moment sehr verwirrend aussehen. Doch was habe ich genau getan? Ich habe eigentlich hier nichts weiter gemacht, als eine neue Klasse mit dem Namen LinkColumn von der Klasse CLinkColumn abgeleitet und habe drei Eigenschaften (filter, name, sortable) definiert. Hinzu habe ich noch zwei Methoden (renderFilterCellContent und renderHeaderCellContent) aus der Klasse CDataColumn kopiert. Das Ergebnis was daraus resultiert, ist eine Möglichkeit mit der es mir möglich wird, einen Zelleninhalt zu verlinken unter Angabe eines eigenen Ziels und der Verwendung einer Eigenschaft aus dem CActiveRecord. Dies sieht dann folgendermaßen aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$this->widget('bootstrap.widgets.CGridView', array(
  'id'=>'kunden-grid',
  'type'=>'striped bordered condensed',
  'dataProvider'=>$model->search(),
  'filter'=>$model,
  'summaryText'=>'',
  'columns'=>array(
    'id',
    array(
      'class'=>'LinkColumn',
      'name'=>'firma',
      'labelExpression'=>'$data->firma',
      'urlExpression'=>'array("view", "id"=>$data->id)',
    ),
    'strasse',
    'plz',
    'ort',
  ),
));

Ich habe diesen ganzen Aufwand eigentlich nur betrieben, um hier noch weiter arbeiten zu können. Hier ging es mir nicht mehr um die Verlinkung einer Externen Seite, sondern um Asyncron daten vom Server holen zu können. Ich suchte eine Möglichkeit, Ajax Links zu generieren, die auch nach dem Pager noch funktionieren. Das Problem mit dem standard Yii Gridview ist, dass ich zwar Ajax Links via CHTML::ajaxLink() auch in eine Zelle generieren kann. Da jedoch das Gridview je Filterauswahl oder Pager Seitenauswahl via Ajax geupdated wird, funktionieren die Ajax Links nicht mehr. Hier musste eine andere Lösung her. Mit meiner neuen LinkColumn Klasse, ist es ganz einfach möglich, eigene Ajax Links zu generieren, die vollkommen unabhängig von Yii sind. Mit folgendem Code generiere ich meine Ajax Links:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$this->widget('bootstrap.widgets.CGridView', array(
  'id'=>'kunden-grid',
  'type'=>'striped bordered condensed',
  'dataProvider'=>$model->search(),
  'filter'=>$model,
  'summaryText'=>'',
  'columns'=>array(
    'id',
    array(
      'class'=>'LinkColumn',
      'name'=>'notice',
      'labelExpression'=>'Notiz',
      'urlExpression'=>'array("view", "id"=>$data->id)',
      'linkHtmlOptions'=>array('onclick'=>'js:$.ajax({url: $(this).attr("href"),success: function(data){$("#target_id").html(data);}}); return false;'),
    ),
    'strasse',
    'plz',
    'ort',
  ),
));

Was passiert hier genau? Nun ich füge eigentlich nur noch dem verlinkenden A-Tag ein weiteres Attribut “onclick” hinzu und fülle dieses mit einem jQuery Kommando. Vorraussetzung hierfür ist natürlich, dass jQuery standardmäßig auf dieser Seite eingebunden ist. Mit dem jQuery Befehl, führe ich eine Asyncrone Abfrage an den Server durch und kann mir die zurückgelieferten Inhalte hier in einem HTML-Element ausgeben lassen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert