Yii2 - Converting from Bootstrap3 to Bootstrap4
This article has been written because while conversion is a largely pain-free process, there are some minor issues. These are not difficult to solve, but it is not immediately obvious where the problem lies.
1 - Install Bootstrap4 My preference is to simply use composer. Change composer.json in the root of your project:
- find the line that includes Bootstrap3.
Copy the line, and change the new line:
- change bootstrap to bootstrap4
- Now head over to https://github.com/yiisoft/ - the Yii2 repository on Github
- search for bootstrap, find the Bootstrap 4 repository and see what the current version is. As of January 2020, https://github.com/yiisoft/yii2-bootstrap4 showed the current version was 2.0.8
- Change the version string to that version number, and also change the ~ to ^
- After this, you should have something like this below, maybe with higher version numbers:
"yiisoft/yii2-bootstrap" : "~2.0.6", "yiisoft/yii2-bootstrap4" : "^2.0.8",
- Save the file, then run 'composer update'
- Use your IDE, text editor or whatever other means you have at your disposal to find all occurrences where bootstrap is used and change it bootstrap4. My suggestion is to search for the string
yii\bootstrap\
and change it toyii\bootstrap4\
. However, be careful - your IDE may require the backslash to be escaped. For example, Eclipse will find all files with the string easily, but the search string must have double-backslashes, while the replacement string must be left as single ones. - Now run all your tests and fix the problems that have arisen. Most of the failures will come from the fact that the Navbar no longer works, most likely. It's still there, just being rendered differently, and in my case it was invisible. This is because Bootstrap4 has changed some elements of the navbar. In my case, 14 tests failed - many of which failed due to the use of navbar content in some manner, such as looking for the Login link to infer whether the user is logged in or not.
- You're not going to fix these issues without understanding them, so take a look at https://getbootstrap.com/docs/4.0/migration/. In particular, look at what has changed regarding the Navbars. The most meaningful is that Bootstrap4 no longer specifies a background, where Bootstrap3 did.
- Open up frontend/viewslayouts/main.php in your editor, then look at your site in the browser. In my case no navbar, except for the Brand, and that is because I changed this from what was delivered as part of the Yii2 template, and it included a background. Since the rest of it was standard, there was nothing else - no ribbon strip, and no menu entries, although mousing into the area would show the links were there and could be clicked.
- Find the line that starts with
NavBar::begin
and look at it's class options. In my case they were the original:'class' => 'navbar-inverse navbar-fixed-top'
- As I said before, no background is included, so add one: bg-dark - and check again. Now there's the ribbon back again, but no menu items.
- Right-click on the ribbon and select "Inspect Element", or do whatever you have to do in your browser to inspect the page source. Looking at that starts to give you clues over what the navbar is doing. Looking at that, and referring back to the Bootstrap4 migration guide, I had the impression that neither navbar-inverse nor navbar-fixed-top were doing anything. So I removed those, and when refreshing the page, confirmed there were no changes.
- More reading on the Bootstrap website gave me the bg-dark I mentioned earlier, and for the text, navbar-light or navbar-dark produced results.
- now I had no menu items, but I did have a button that expanded the menu. Inspecting it's properties told me it was 'navbar-toggler', and the Bootstrap website told me it new to Bootstrap4, while it and was collapsed by default, 'navbar-expand' would expand it by default. That's cool - I reckon I'm going to add a setting for logged-in users that let them choose which they prefer. In the end, I opted for navbar-expand-md, which keeps it expanded unless the screen width is tight.
- Find the line that starts with
At the end of all this, I had the class line changed to something which gave me a navbar very similar to the original:
//Bootstrap3: 'class' => 'navbar-inverse navbar-fixed-top',
//Changed for Bootstrap4:
'class' => 'navbar navbar-expand-md navbar-light bg-dark',
Breadcrumbs
Note - March 2020: This entire section on Breadcrumbs may no longer be an issue. While I've left the section in as a tutorial, before making any changes read what Davide has to say in the user comments.
So, that fixed my navbar. Next, I noticed that the breadcrumbs were not quite right - the slash separating the path elements was no longer there. Preparing for a lot of debugging, I went to the Bootstrap site to look for a little inspiration. I didn't need to look any further - Bootstrap 4 requires each Breadcrumb element to have a class of "breadcrumb-item". After I spent a little time looking at vendors/yiisoft/yii2/widgets/Breadcrumbs.php to get some understanding of the issue, I discovered all that's needed is to change the itemTemplate and activeItemTemplate. Of course, since these are part of the Yii2 framework, you don't want to change that file, otherwise, it will probably get updated at some stage, and all your changes would be lost. Since both of these attributes are public, you can change them from outside the class, and the easiest place to do this is in frontend/views/main.php:
`
html
<div class="container">
<?= Breadcrumbs::widget([
'itemTemplate' => "\n\t<li class=\"breadcrumb-item\"><i>{link}</i></li>\n", // template for all links
'activeItemTemplate' => "\t<li class=\"breadcrumb-item active\">{link}</li>\n", // template for the active link
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
<?= Alert::widget() ?>
<?= $content ?>
</div>```
Data Grid ActionColumn One of my pages was a data grid generated for me by gii. On each row it has a set of buttons that you can click to view, edit or delete the row. Under Bootstrap 4, the ActionColumn disappeared. Viewing the page source showed me it was there, but I couldn't see it or click on it. Going to the migration guide, it turns out that Bootstrap 3 includes icons, but Bootstrap 4 doesn't. I got a lot of help from a question asked in the Yii2forum.. In the end, my solution was to get a local copy of FontAwesome 5 by including the line "fortawesome/font-awesome": "^5.12.1" in the require section of composer.json, and then choosing the icons that I wanted. I spent a lot of time figuring out how to do this, but when I was done, it seemed almost anti-climactic in it's simplicity. This is what I did in my data form:
['class' => 'yii\grid\ActionColumn',
'buttons' => [
'update' => function($url,$model) {
return Html::a('<i class="fas fa-edit"></i>', $url, [
'title' => Yii::t('app', 'update')
]);
},
'view' => function($url,$model) {
return Html::a('<i class="fas fa-eye"></i>', $url, [
'title' => Yii::t('app', 'view')
]);
},
'delete' => function($url,$model) {
return Html::a('<i class="fas fa-trash"></i>', $url, [
'title' => Yii::t('app', 'delete')
]);
}
]
],
Functional Tests
Not seeing anything more visually, at least nothing that was obvious, I now ran the suite of tests. These were all previously passing, but now several of them failed. One of them was the Contact Form, so I ran that one separately and the tests informed me they were failing because they couldn't see the error message:
1) ContactCest: Check contact submit no data
Test ../frontend/tests/functional/ContactCest.php:checkContactSubmitNoData
Step See "Name cannot be blank",".help-block"
Fail Element located either by name, CSS or XPath element with '.help-block' was not found.
I, on the other hand, could see the error messages on the form, so I used the browser's page source and discovered that the css class was no longer "help-block", it had changed to "invalid-feedback". Easy enough - in frontend/tests/_support/FunctionalTester.php, I changed the expected css class:
public function seeValidationError($message)
{
$this->see($message, '.invalid-feedback');
}
Of course, this little excerpt is just an example. I found the same thing had to be done in several locations, but all were easily found and resolved.
After this, running my tests pointed me to no other problems, but I don't expect that to mean there aren't any other problems. While everything seems to be working so far, I expect there are more issues hiding in the woodwork. Somehow, those problems don't seem quite so insurmountable anymore.
Nice guide!
Btw, you might want to upgrade your Alert Widget too.
How?
In basic template, go to Widgets/Alert.php
In advanced template, go to common/widgets/Alert.php
Change
> class Alert extends \yii\bootstrap\Widget
Into
> class Alert extends \yii\bootstrap4\Widget
Finally some comprehensive guide on this, thanks!
Anyway, for breadcrumbs, most of the issues can be solved by replacing:
use yii\widgets\Breadcrumbs;
with:
use yii\bootstrap4\Breadcrumbs;
Bootstrap v3 should be removed and not kept if you will use Bootstrap v4. But removing it will cause other errors.
If you get an error:
`
phpFailed to instantiate component or class "yii\bootstrap\BootstrapAsset
you should update BootstrapAsset ```php // file: assets/AppAsset.php public $depends = [ 'yii\web\YiiAsset', * 'yii\bootstrap4\BootstrapAsset', * ];
For Widget error, follow Andre Rahardjo's advice.
['class' => 'yii\grid\ActionColumn', 'buttons' => [ 'update' => function($url,$model) { return Html::a('<i class="fas fa-edit"></i>', $url, [ 'title' => Yii::t('app', 'update') ]); }, 'view' => function($url,$model) { return Html::a('<i class="fas fa-eye"></i>', $url, [ 'title' => Yii::t('app', 'view') ]); }, 'delete' => function($url,$model) { return Html::a('<i class="fas fa-trash"></i>', $url, [ 'title' => Yii::t('app', 'delete') ]); } ] ],
In delete action we must use METHOD POST,
So it will be:
`
php'delete' => function($url,$model) { return Html::a(FA::icon('trash'), $url, [ 'title' => Yii::t('app', 'delete'), 'class' => 'btn btn-danger', 'data' => [ 'confirm' => 'Are you sure you want to delete this item?', 'method' => 'post', ], ]); }
You guys build such a nice looking FrameWork and want to get new Users to work with it.
But insted of beeing able to start strait away, i have to f* nightmare to simply upgrade to Bootstrap 4.
Make that part easy. New ppl want to learn the framework not searching dozens of files because an older boostrap is nearly hardcoded...
my 5 cent
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.