In this callback it is decided if the column will be rendered.
data
Closure / null
null
custom data callback (see example)
sort
Closure / null
null
custom sort query callback (see example)
search
Closure / null
null
custom search query callback (see example)
Example
function (User $user) { //entity from getEntityClass
//you can return what ever you want ...
return $user->getId() . " " . $user->getUsername();
},
'sort' => function (QueryBuilder $qb, $direction) { //execute if user sort this column
$qb->addOrderBy('username', $direction);
},
'search' => function (Composite $composite, QueryBuilder $qb, $search) {
//first add condition to $composite
//don't forget the ':' before the parameter for binding
$composite->add($qb->expr()->like($dql, ':username'));
//then bind search to query
$qb->setParameter("username", $search . '%');
}
))">
//use statements for search and sort optionuseDoctrine\ORM\Query\Expr\Composite;
useDoctrine\ORM\QueryBuilder;
->add('username', TextColumn::class, array(
'title' => 'Username',
'emptyData' => "No Username found.",
//optional overrides ...'data' => function (User$user) { //entity from getEntityClass//you can return what ever you want ... return$user->getId() . " " . $user->getUsername();
},
'sort' => function (QueryBuilder$qb, $direction) { //execute if user sort this column$qb->addOrderBy('username', $direction);
},
'search' => function (Composite$composite, QueryBuilder$qb, $search) {
//first add condition to $composite//don't forget the ':' before the parameter for binding$composite->add($qb->expr()->like($dql, ':username'));
//then bind search to query$qb->setParameter("username", $search . '%');
}
))
search Option:
Paramenter name
Description
Composite $composite
In the global search all columns are connected as or. In the advanced search all columns are combined with an and-connection. With $composite more parts can be added to the query. Composite is the parent class of AndX and OrX.
QueryBuilder $qb
$qb holds the use QueryBuilder. It is the same instance as can be queried with getQueryBuilder() in the table class.
$search
The search in the type of a string.
BooleanColumn
Represents column with boolean values.
Options
All options of TextColumn.
advancedSearchType is set to checkbox by default.
filter is set to array(BooelanChoiceFilter::class, array()) by default.
Array of route parameters. The key is the parameter of the route. The value is the property path.
attr
array
[ ]
Array of any number of attributes formatted as HTML attributes. The array ["class" => "btn btn-success"] is formatted as class="btn btn-success".
Example
useHelloSebastian\HelloBootstrapTableBundle\Columns\LinkColumn;
->add('department.name', LinkColumn::class, array(
'title' => 'Department',
'routeName' => 'show_department', // this option is required'routeParams' => array(
'id' => 'department.id'// "id" is the route parameter of "show_department". "department.id" is the property path to fetch the value for the route parameter.
)
))
If the route parameters cannot be determined automatically based on the entity, user-defined routes can be created by overwriting data. Once data is overwritten, routeName and routeParams are no longer necessary to specify.
sortable, searchable and switchable are disable by default.
formatter is set to defaultActionFormatter.
And:
Option
Type
Default
Description
buttons
array
[ ]
array of buttons configuration as array.
Example
'Actions',
'width' => 120, //optional
'buttons' => array(
array(
'displayName' => 'show',
'routeName' => 'show_user',
'additionalClassNames' => 'btn-success',
'attr' => array(
'title' => 'Show',
// any number of other attributes
)
),
array(
'displayName' => 'edit',
'routeName' => 'edit_user',
// 'classNames' => 'btn btn-xs' (see below for more information)
'additionalClassNames' => 'btn-warning',
'addIf' => function(User $user) { // you can use your entity in the function
// In this callback it is decided if the button will be rendered.
return $this->security->isGranted('ROLE_ADMIN');
}
)
)
))">
->add("actions", ActionColumn::class, array( // key "actions" can be chosen freely but must be unique in the table'title' => 'Actions',
'width' => 120, //optional'buttons' => array(
array(
'displayName' => 'show',
'routeName' => 'show_user',
'additionalClassNames' => 'btn-success',
'attr' => array(
'title' => 'Show',
// any number of other attributes
)
),
array(
'displayName' => 'edit',
'routeName' => 'edit_user',
// 'classNames' => 'btn btn-xs' (see below for more information)'additionalClassNames' => 'btn-warning',
'addIf' => function(User$user) { // you can use your entity in the function// In this callback it is decided if the button will be rendered.return$this->security->isGranted('ROLE_ADMIN');
}
)
)
))
ActionButtons
Option
Type
Default
Description
displayName
string
""
label of button
routeName
string
""
route name
routeParams
array
["id"]
Array of property value names for the route parameters. By default is id set.
classNames
string
""
CSS class names which added directly to the a element. Overrides default class names from YAML config.
additionalClassNames
string
""
You can set default class names in YAML config. Then you can add additional class names to the button without override the default config.
attr
array
[ ]
Array of any number of attributes formatted as HTML attributes. The array ["title" => "Show"] is formatted as title="Show". The href and class attributes are created by the other options and should not be defined here.
addIf
Closure
function($entity) {return true;}
In this callback it is decided if the button will be rendered.
YAML config options are set to all buttons. If you want override global options from YAML config use classNames option.
Filters
Filters can be used to generate predefined queries. In addition, different input fields for the filters are displayed (currently only under the Advanced Search).
TextFilter
With the TextFilter you can filter by text within the column. TextFilter is set by default to all columns.
Options
Option
Type
Default
Description
advSearchFieldFormatter
string
"defaultAdvSearchTextField"
Set JavaScript function name to format input field.
placeholder
string / null
title option from column with " ..."
Set HTML placeholder for input field.
If you want to change advSearchFieldFormatter, you also need to create a JavaScript function with the same name in the window scope. As an example here is the default function:
`;
};">
//value can be undefinedwindow.defaultAdvSearchTextField=function(field,filterOptions,value){letval=value||"";return`${val}" class="form-control" name="${field}" placeholder="${filterOptions.placeholder}" id="${field}">`;};
Example
useHelloSebastian\HelloBootstrapTableBundle\Filters\TextFilter;
->add('firstName', TextColumn::class, array(
'title' => 'First name',
'filter' => array(TextFilter::class, array(
'placeholder' => 'Enter first name ...'
))
))
ChoiceFilter
With the ChoiceFilter you can create a select input field.
Options
All Options from TextFilter.
advSearchFieldFormatter is set to defaultAdvSearchChoiceField.
And:
Option
Type
Default
Description
choices
array
[ ]
Key - Values pair of choices. Key: value attribute of select field; Value: display name of options in select field.
selectedValue
string | int
"null"
Default selected value when table is rendered.
Example
useHelloSebastian\HelloBootstrapTableBundle\Filters\ChoiceFilter;
->add('department.name', TextColumn::class, array(
'title' => 'Department',
'filter' => array(ChoiceFilter::class, array(
'choices' => array(
'null' => 'All', //null is special key word. If 'null' is set QueryBuilder skip this column.'IT' => 'IT',
'Sales' => 'Sales'
)
))
))
BooleanChoiceFilter
BooleanChoiceFilter is a special ChoiceFilter with default choices and query expression. The expression is optimized for boolean values.
Options
All Options from ChoiceFilter.
If you use BooleanChoiceFilter inside a BooleanColumn, the allLabel, trueLabel and falseLabel options from BooleanColumn are taken for null, true and false for the choices option by default.
If not choices is set to:
array(
"null" => "All", // key must be "null", if you want allow to show all results
"true" => "True", // key must be "true", if you want allow true
"false" => "False" // key must be "false", if you want allow false
)">
"choices" => array(
"null" => "All", // key must be "null", if you want allow to show all results"true" => "True", // key must be "true", if you want allow true"false" => "False"// key must be "false", if you want allow false
)
Example
'is active',
'filter' => array(BooleanChoiceFilter::class, array( // only if you want to override the choices
'choices' => array(
"null" => "Alle", // instead of "all"
"true" => "Ja", // instead of "yes"
"false" => "Nein" // instead of "no"
)
)),
'trueLabel' => 'yes',
'falseLabel' => 'no'
))">
->add("isActive", BooleanColumn::class, array(
'title' => 'is active',
'filter' => array(BooleanChoiceFilter::class, array( // only if you want to override the choices'choices' => array(
"null" => "Alle", // instead of "all""true" => "Ja", // instead of "yes""false" => "Nein"// instead of "no"
)
)),
'trueLabel' => 'yes',
'falseLabel' => 'no'
))
CountFilter
With the CountFilter you can filtering and sorting by counting OneToMany relations.
Options
All Options from TextFilter.
And:
Option
Type
Default
Description
condition
string
"gte"
Operation to compare counting. Available options: "gt", "gte", "eq", "neq", "lt", "lte"
primaryKey
string
"id"
Primary key of the target entity in the OneToMany relation. For example: A user is in one deparment. One department has many users. In the user entity there is a $department attribute that is pointing to the department entity. With this option you specify the primary key of the department entity (the target entity).
Table Dataset are provided directly to the bootstrap-table as data-attributes and are a collection of setting options for the table. For more information check bootstrap-table documentation: https://bootstrap-table.com/docs/api/table-options/
// src/Controller/UserController.phppublicfunctionindex(Request$request, HelloBootstrapTableFactory$tableFactory) : Response
{
$table = $tableFactory->create(UserTable::class);
// other options will be merged.$table->setTableDataset(array(
'locale' => 'de-DE'
));
// ...
}
YAML config:
YAML config options are set to all tables. If you want override global options from YAML config use setTableDataset method in or outside from HelloBootstrapTable.
# config/packages/hello_table.yamlhello_bootstrap_table:
table_dataset_options:
locale: 'de-DE'# see Table Dataset Options
Table Options
All options that should not be provided directly as data-attributes of the table are managed here.
YAML config options are set to all tables. If you want override global options from YAML config use setTableDataset method in or outside from HelloBootstrapTable.
# config/packages/hello_table.yamlhello_bootstrap_table:
table_options:
enableCheckbox: false # see Table Options
Common Use-Cases
Custom Doctrine Queries
Sometimes you don't want to display all the data in a database table. For this you can "prefilter" the Doctrine query.
Example
create(TestTable::class);
//then you can access the QueryBuilder from the table
$table->getQueryBuilder()
->andWhere('department.name = :departmentName')
->setParameter('departmentName', 'IT');
$table->handleRequest($request);
if ($table->isCallback()) {
return $table->getResponse();
}
return $this->render("index.html.twig", array(
"table" => $table->createView()
));
}">
/** * @Route("/", name="default") */publicfunctionindex(Request$request, HelloBootstrapTableFactory$tableFactory)
{
//first create a instance of your table$table = $tableFactory->create(TestTable::class);
//then you can access the QueryBuilder from the table$table->getQueryBuilder()
->andWhere('department.name = :departmentName')
->setParameter('departmentName', 'IT');
$table->handleRequest($request);
if ($table->isCallback()) {
return$table->getResponse();
}
return$this->render("index.html.twig", array(
"table" => $table->createView()
));
}
Default table sorting
bootstrap-table allows you to specify a default sort order. For this purpose there are two options "sort-name" and "sort-order". These can be set by the setTableDataset method. "sort-name" expects the dql (or if set field name) of the column. "sort-order" can be set by "asc" or "desc".
// inside table classprotectedfunctionbuildColumns(ColumnBuilder$builder, $options)
{
$this->setTableDataset(array(
'sort-name' => 'firstName', // dql (or if set field name) of column'sort-order' => 'desc'// or asc
));
$builder->add('firstName', TextColumn::class, array(
'title' => 'First name'
));
}
// outside table class$table = $tableFactory->create(UserTable::class);
$table->setTableDataset(array(
'sort-name' => 'firstName',
'sort-order' => 'desc'
));
HelloBootstrapTable provides a helper method setDefaultSorting to set the default sort order.
You can expand rows in bootstrap-table. This option is called "detail view" and can be enabled in the datasets (by default this is disabled). For displaying the content of detail-view a formatter is needed (also to be specified in datasets). In the formatter you have access to the data of the table row. For complex representations Twig can also be used. See the example below.
protectedfunctionbuildColumns(ColumnBuilder$builder, $options)
{
//enable detail-view and set formatter$this->setTableDataset(array(
'detail-view' => true,
'detail-formatter' => 'detailViewFormatter'
));
$builder// other columns ...// detailView is not a database field and can be named as you like.// but the column should not displayed in the table (HiddenColumn)
->add('detailView', HiddenColumn::class, array(
// override data callback (as attribute you can access the entity that you specified in getEntityClass())'data' => function (User$user) {
// now you can return everthing you want (twig render included)// twig is provided by HelloBootstrapTablereturn$this->twig->render('user/detail_view.html.twig', array(
'user' => $user
));
}
));
}
To display detailView as content of the expanded table row a formatter function must be created and detailView must be returned. Remember to create the formatter before calling {{ hello_bootstrap_table_js() }}.
// index => index of row inside table// row => data object of the row// element => row DOM elementwindow.detailViewFormatter=function(index,row,element){// detailView matched with the name from add('detailView', HiddenColumn::class). If you use a different name you must changed it here too.returnrow.detailView;};
Alternative you can of course create your HTML with JavaScript inside the formatter.
Use Icons as action buttons
To save space in the table, it makes sense to use icons instead of written out buttons. This is easily possible by using HTML instead of a word in the displayName option of the action buttons.
In this update, missing parameter types and return types to all internal and external functions have been added.
Also fixed a bug with the new enableTotalCountCache option. (see #34)
Breaking Changes:
Missing types were also added to the methods in the table classes. Among them, the methods buildColumns, getEntityClass, configureTableDataset and configureTableOptions are affected.
buildColumns - before:
protected function buildColumns(ColumnBuilder $builder, $options) { }
after:
protected function buildColumns(ColumnBuilder $builder, array $options): void { }
getEntityClass - before:
protected function getEntityClass() { }
after:
protected function getEntityClass(): string { }
configureTableDataset - before:
public function configureTableDataset(OptionsResolver $resolver) { }
after:
public function configureTableDataset(OptionsResolver $resolver): void { }
configureTableOptions - before:
public function configureTableOptions(OptionsResolver $resolver) { }
after:
public function configureTableOptions(OptionsResolver $resolver): void { }
When large and complex tables are built over multiple entities and have several 100k records, the initial count of the total amount of records takes a very long time. This is most likely due to the LEFT JOINS.
With the option enableTotalCountCache the result of the count can now be cached.
If filter control and and the global search are active, the value of the global search "search" is set when entering a column filtering.
This was already fixed in bootstrap-table in 2019, but the extension "cookie" sets the value again. Therefore, the extension cookie is deactivated for now. Compare https://github.com/wenzhixin/bootstrap-table/issues/3966
This fix resolves a bug in LinkColumn. The option "routeParams" was changed so that the key represents the route parameter. The Value specifies the property path for the value of the route parameters.
The ReadMe file has also been modified accordingly.
Add CountColumn to provide a solution to display counts of OneToMany relations. CountColumn provide filter and sort functions and display the count of OneToMany relations in the table.
In this PR the column option search callback function interface was changed.
After:
'search' => function (Composite $composite, QueryBuilder $qb, $search) {}
In the table you know the attribute name of the column. Therefore, the $dql parameter is no longer needed.
The $key parameter is used to uniquely bind the search parameters in the query. In the callback function you can provide a unique name for the search parameters yourself.
Hello,
Could you please remove the deprecation and ensure compatibility with Symfony >= 5.4?
Method "Symfony\Component\Config\Definition\ConfigurationInterface::getConfigTreeBuilder()" might add "TreeBuilder" as a native return type declaration in the future. Do the same in implementation "HelloSebastian\HelloBootstrapTableBundle\DependencyInjection\Configuration" now to avoid errors or add an explicit @return annotation to suppress this message.
Hello,
First, really thanks for your works ! I'm new on it and on Boostrap table ! I want to create a custom filter (using multiple field with checkbox, dateInterval , ....). My question is, if I have a form, how can I pass all the value to the datatable, and how can I refresh the table manually !
Cheers !
opened by manaka02 2
Releases(v0.8.1)
v0.8.1(Aug 17, 2022)
FIX: Filter control and search (https://github.com/HelloSebastian/hello-bootstrap-table-bundle/pull/28)
html-sanitizer is a library aiming at handling, cleaning and sanitizing HTML sent by external users (who you cannot trust), allowing you to store it and display it safely. It has sensible defaults to provide a great developer experience while still being entierely configurable.