How to customize links for breadcrumbs widget for Yii?
I can change the property tagName, but it for container. I want to change a tag for each links from a to li. How can I do it?
Well there's no setting/property value that you can specify for the default CBreadcrumbs widget class that will give you <li>. You can confirm this if you check out its run() method. In the source you can see this:
public function run(){
// code
foreach($this->links as $label=>$url)
{
if(is_string($label) || is_array($url))
$links[]=CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url);
else
$links[]='<span>'.($this->encodeLabel ? CHtml::encode($url) : $url).'</span>';
}
// more code
}
So what you'll have to do is extend this class and specify your own run method, where you can use <li> or CHtml::tag('li',//other options) instead of the default CHtml::link.
Edit:
Although i would suggest enclosing the <a> for each link with a <li> (instead of replacing it):
$links[]='<li>'.CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url).'</li>';
You can do that with 'activeLinkTemplate' and 'inactiveLinkTemplate' properties:
$this->widget('zii.widgets.CBreadcrumbs',
array('tagName'=>'ul',
'homeLink'=>'<li>'.CHtml::link('Home', array('/')).'</li>',
'activeLinkTemplate'=>'<li>{label}</li>',
'inactiveLinkTemplate'=>'<li class="active">{label}</li>',
'htmlOptions'=> array('class'=>'breadcrumb'),
'separator'=>' / ',
'links'=>$this->breadcrumbs,
));
Or U can write 'homeLink'=>false. But in this case U'll have to set Home url every time with $this->breadcrumbs.
Related
My page has this directive #page "/sales/reports" so it loads at https://localhost/sales/reports route.
I want to create link Report 1 that will lead to a sub-page /sales/reports/{id} - for example https://localhost/sales/reports/8c5b8c1c-12b5-43ee-92c9-8d3bcb8644a4 but not sure what do I put in href of my anchor. When I simply put Report 1 link has a form of https://localhost/8c5b8c1c-12b5-43ee-92c9-8d3bcb8644a4. Do I need to hard-code Report 1 or there is a smarter way?
The term 'subpage' does not really exist.
There are just 'pages' and they have 'routes'. Sometimes the route appears nested, as in your example, but this does not make it a 'subpage'.
The answer to your question is that, yes, you need to include the route to the 'page' you want to go to.
<a href=#($"sales/reports/{#myGuid}")>Report 1</a>
That doesn't necessarily mean hardcoding in the page itself. You might create a helper class that does that for you. For example:
class ReportPathCreator
{
public static string ReportRouteFor(Guid reportGuid) => $"sales/reports/{reportGuid}";
}
Then use:
<a href=#(ReportPathCreator.ReportRouteFor(myGuid))>Report 1</a>
Then, if you choose to change the route where reports are hosted, you only need to change it in the helper class and all anchor elements in your site will automatically pick up that new route.
UPDATE
You can also use the static class to generate a template for you to use instead of #page directive:
class ReportPathCreator
{
public static string ReportRouteFor(Guid reportGuid) => $"sales/reports/{reportGuid}";
public static string ReportTemplate = "sales/reports/{reportGuid:guid}";
}
And then, instead of #page directive, use:
#attribute [Route(ReportPathCreator.ReportTemplate)]
I have written a tag helper that I can use as follows...
<mytaghelper attr1="jim"></mytaghelper>
I would like to be able to shorten this to just...
<mytaghelper attr1="jim">
...or at least...
<mytaghelper attr1="jim"/>
However, I can't get this to work. Here is some sample code for the Process method...
public override void Process(TagHelperContext context, TagHelperOutput output) {
output.TagName = "div";
output.PreContent.SetHtmlContent("<div>");
output.Content.SetHtmlContent("OUTPUT HTML GOES HERE");
output.PostContent.SetHtmlContent("</div>");
output.Attributes.Clear();
}
I have tried adding a TagStructure setting to the HtmlTargetElement attribute on the class...
[HtmlTargetElement("mytaghelper", TagStructure = TagStructure.WithoutEndTag)]
...but it doesn't seem to make any difference. <mytaghelper attr1="jim"/> generates <div /> and <mytaghelper attr1="jim"></mytaghelper> generates <div></mytaghelper>.
If I set the TagStructure to NormalOrSelfClosing then included a closing tag works, but <mytaghelper attr1="jim"/> gives an empty <div />
Anyone able to explain what I need to do?
TagStructure.WithoutEndTag is able to write the tag with only a start tag or self-closing, but the output would be <div > or <div/> . Self-closing anchor tags are not valid HTML, so you wouldn't want to create one, but you might want to create a tag helper that's self-closing. Tag helpers set the type of the TagMode property after reading a tag. Add the below code line Inside the process method:
output.TagMode = TagMode.StartTagAndEndTag;
Take a moment to read Author Tag Helpers in ASP.NET Core which covers this perfectly .
The correct syntax is:
[HtmlTargetElement("mytaghelper", TagStructure = TagStructure.WithoutEndTag)]
Which should be applied to the taghelper class, not the Process method. You may already be doing that, but it wasn't clear in your question. I believe you still must use the self-closing tag syntax (/>) for it work, though.
I'm trying to follow the URL of a hidden Log Out link. The HTML looks like this:
<li id="wp-admin-bar-logout"><a class="ab-item" href="http://www.ananda.org/wp-login.php?action=logout&_wpnonce=f633c2d0a4">Log Out</a> </li>
Getting the element is straightforward:
$link = $this->byXPath( '//*[#id="wp-admin-bar-logout"]/a' );
Can I get attributes?
You can get attributes of elements, apparently, though I couldn't find this documented anywhere.
Here's the complete solution I used:
protected function doLogout() {
$this->url('/wp-admin');
$link = $this->byXPath( '//*[#id="wp-admin-bar-logout"]/a' );
$this->url( $link->attribute('href') );
}
So i am working in an app that uses de CGridView extensively but I am porting a webapp from a proprietary framework to Yii. So the CSS files are already written and have been working up until now.
The thing is that in my CGridView widget the headers of columns are enclosed in a TR tag and I have got no clue on where I can add a class attribute to this tag. I've read the documentation and now how to change each header cell individually but not the whole TR.
Thanks for your help!
Ran into a similar problem however as our CSS is for a legacy system I didn't want to roll in yet more CSS rules. In addition I needed support for extra things such as targeting the header with a specific CSS class on the table row and putting in first/last css classes on the items.
To achieve a first/last css on the items you do not need to extend the GridView and can use the handy rowCssClassExpression parameter.
To achieve my second objective of injecting a CSS class into the 'table thead tr' element I did have to override the renderTableHeader() method.
I strongly advise you only consider this route as a last resort because if you update the version of Yii it is conceivable that they make changes that are not backwards compatible with the renderTableHeader() method. Alternatively you could write a test case that runs your widget through a DOM checker to confirm that you only have 1 table element, 1 thead element, 1 tbody element etc...
Yii::import('zii.widgets.grid.CGridView');
class FXSGridView extends CGridView {
public $headerCssClass = 'columnHeadings';
public $itemsCssClass = 'grey';
public $rowCssClassExpression = '$this->rowCssClassFunction($row, $data);';
public $rowCssClass = array('odd','even');
public function rowCssClassFunction($row, $data) {
$classes = array();
if ($row == 0) $classes []= 'first';
if ($row == $this->dataProvider->getItemCount() - 1) $classes []= 'last';
// Do flip/flop on defined rowCssClass
if(is_array($this->rowCssClass) && !empty($this->rowCssClass)) $classes []= $this->rowCssClass[$row % count($this->rowCssClass)];
return empty($classes) ? false : implode(' ', $classes);
}
public function renderTableHeader()
{
if(!$this->hideHeader)
{
echo "<thead>\n";
if($this->filterPosition===self::FILTER_POS_HEADER)
$this->renderFilter();
echo '<tr class="' . $this->headerCssClass . ' ">' . "\n";
foreach($this->columns as $column)
$column->renderHeaderCell();
echo "</tr>\n";
if($this->filterPosition===self::FILTER_POS_BODY)
$this->renderFilter();
echo "</thead>\n";
}
else if($this->filter!==null && ($this->filterPosition===self::FILTER_POS_HEADER || $this->filterPosition===self::FILTER_POS_BODY))
{
echo "<thead>\n";
$this->renderFilter();
echo "</thead>\n";
}
}
}
'columns'=>array(
array(
'name'=>'id',
'header'=>'#',
'htmlOptions'=>array('style'=>'width: 50px; text-align: center;', 'class'=>'zzz'),
'headerHtmlOptions'=>array('class'=>'mytheadclass'),
),
The "headerHtmlOptions" is the one that gives a class to the thead cell of this column.
Unfortunately you cannot do this directly, as there is no provision for adding attributes to the header row tags (see source code).
A straightforward solution would be to subclass CGridView as e.g. MyGridView and override the renderTableHeader method to do what you need it to (add some class variables to MyGridView to let it be configurable). I have used this approach many times in similar situations.
If it's just simple changes you need to make, you might be able to use the generated CSS with something like:
table.admins th {border-right:none;text-align:center;}
table.admins th:first-child {text-align:left;}
etc...
or you could use the Yii-generated ids (view the generated HTML):
<th id="admins-grid_c1">
which may or may not be appropriate depending on how many grids you want to apply the css to and your own naming conventions. You could also use JavaScript/jQuery to manipulate the styles but certainly #Jon's suggestion of creating a custom renderTableHeader is going to give you the most control. (I've also used that approach with lists and renderSorter.)
I have two Hyper Links on to a DOJO DIv
var create = dojo.create("div",{
id:"create_links",
className:"iconRow1",
innerHTML:"<a class='popupLink' href='javascript:openCreateDialog()'>Create </a> <span>|</span><a href='javascript:openUploadDialog()'>Batch </a>"
},dojo.query(".ui-jqgrid-titlebar")[0]);
On click of the Batch Hyperlink , i have a function
function openUploadDialog()
{
// Here i want to disable the Create Hyper Link tried this way
dojo.byId('create_links')[1].disabled=true; // Not working
}
See whether i can answer your question.
HTML Part:
<div id="create_links">
g
h
</div>
JS Part:
dojo.addOnLoad(function() {
var a = dojo.query("#create_links a")[1];
dojo.connect(a,'click',function(e){
console.log(e.preventDefault())
})
})
#Kiran, you are treating the return of dojo.byId('create_links') like an array when that statement will return to you a node on the dom.
Also, hyperlinks don't support a disabled attribute to prevent them from being actionable. You could probably create a click handler that returns false to accomplish this type of functionality, or like #rajkamal mentioned, calling e.preventDefault(). #rajkamal also provides a good solution to selection the link properly.