Skip to content

Commit fbf470e

Browse files
committed
[EH] some enhancements
1 parent ea8b4af commit fbf470e

File tree

4 files changed

+125
-84
lines changed

4 files changed

+125
-84
lines changed

README.md

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
This is a package for [Laravel Backpack](https://laravel-backpack.readme.io/docs) and provides CRUD field types which allow to create a related CRUD entity on-the-fly while adding/editing another.
1212

13+
![Screenshot](https://www.file-upload.net/download-13140127/Bildschirmfoto2018-05-21um20.00.23.png.html)
14+
![Screenshot](https://www.file-upload.net/download-13140129/Bildschirmfoto2018-05-21um20.01.18.png.html)
15+
1316
## Install
1417

1518
### Via Composer
@@ -22,16 +25,16 @@ composer require webfactor/laravel-backpack-instant-fields
2225

2326
### EntityCrudController
2427

25-
In the EntityCrudController that is supposed to PROVIDE instant creation (not in the CrudController where you want to USE instant fields!) you have to embed the `CanBeCreatedOnTheFly` trait from this package.
28+
For simplicity add the `InstantFields` trait from this package to all EntityCrudControllers which are supposed to provide "instant fields" or are triggered by "instant fields".
2629

2730
```php
2831
<?php
2932

30-
use Webfactor\Laravel\Backpack\InstantFields\CanBeCreatedOnTheFly;
33+
use Webfactor\Laravel\Backpack\InstantFields\Instantfields;
3134

3235
class EntityCrudController extends CrudController
3336
{
34-
use CanBeCreatedOnTheFly;
37+
use InstantFields;
3538

3639
//
3740
}
@@ -41,30 +44,34 @@ This trait provides all needed route entry points methods and ajax response meth
4144

4245
### Routes
4346

44-
in your routes file you have to add three additional routes for you `CRUD::resource`. For clarity we recommend to use the `with()` helper:
47+
in your routes file you have to add one additional route in your `CRUD::resource` for each Entity that uses the packages trait. For clarity we recommend to use the `with()` helper:
4548

4649
```php
4750
<?php
4851

4952
CRUD::resource('entity', 'EntityCrudController')->with(function () {
50-
Route::get('entity/ajax/create', 'EntityCrudController@ajaxCreate');
51-
Route::get('entity/ajax', 'EntityCrudController@ajaxIndex');
52-
Route::post('entity/ajax', 'EntityCrudController@ajaxStore');
53+
Route::match(['get', 'post'],'entity/ajax/{create?}', 'EntityCrudController@handleAjaxRequest');
5354
});
5455
```
5556

57+
The trait/route will handle three situations for you:
58+
59+
- search on triggered entity
60+
- retrieve the HTML for the modal
61+
- store entity from modal
62+
5663
### Available Fields
5764

5865
There are two field types available in this package which allow you an instant creation of related models (1-n and n-m). They are modified versions of the equivalent field types that already exist in Laravel Backpack:
5966

6067
- [select2_from_ajax](https://laravel-backpack.readme.io/docs/crud-fields#section-select2_from_ajax)
6168
- [select2_from_ajax_multiple](https://laravel-backpack.readme.io/docs/crud-fields#section-select2_from_ajax_multiple)
6269

63-
To use instant creation capability of these field types you have to add the `on-the-fly` key
70+
To use instant creation capability of these field types you have to add the `on-the-fly` key and set a name for the entity.
6471

6572
```
6673
'on_the_fly' => [
67-
'create_view' => backpack_url('entity/ajax/create'),
74+
'entity' => 'entity' // e.g. user, contact, company, job etc...
6875
]
6976
```
7077

@@ -81,58 +88,72 @@ Example:
8188
'model' => Entity::class,
8289
'entity' => 'entity',
8390
'attribute' => 'name',
84-
'data_source' => backpack_url('entity/ajax'),
8591
'placeholder' => 'Choose',
8692
'minimum_input_length' => 0,
8793
'on_the_fly' => [
88-
'create_view' => backpack_url('entity/ajax/create'),
94+
'entity' => 'entity',
8995
],
9096
],
9197
```
9298

9399
## Multiple instant fields
94100

95-
If you want to use more than one instant field in a CrudController you have to define separate names for each so that JQuery is able to trigger the modals in the right way.
96-
97-
### EntityCrudController
98-
99-
In the EntityCrudController that provides instant creation you have to set the `$ajaxEntity` property by using the setter in the `setup()`-method:
101+
If you want to use more than one instant field in a CrudController you have to set the `$ajaxEntity` property by using the setter in the `setup()`-method of the EntityCrudController that is triggered by an "instant field". This has to be the same name as in the field definition:
100102

101103
```php
102104
<?php
103105

104-
use Webfactor\Laravel\Backpack\InstantFields\CanBeCreatedOnTheFly;
106+
use Webfactor\Laravel\Backpack\InstantFields\InstantFields;
105107

106108
class EntityCrudController extends CrudController
107109
{
108-
use CanBeCreatedOnTheFly;
110+
use InstantFields;
109111

110112
public function setup()
111113
{
112114
// other Backpack options
113-
$this->setAjaxEntity('name_of_entity');
115+
116+
$this->setAjaxEntity('entity');
114117

115118
// fields/columns definitions
116119
}
117120
}
118121
```
119122

120-
### Field definition
123+
## Customization
124+
125+
### Modal view
121126

122-
In the field definition you have to add `entity` to the `on-the-fly` key and give it the exact same name as in the EntityCrudController above.
127+
By default the modal is loaded automatically by using `entity` in `on_the_fly` of the field definition resulting in `backpack_url($field['on_the_fly']['entity']).'/ajax/create'` in the field blade.
128+
129+
You can overwrite this behavior by setting a `create_view` attribute:
123130

124131
```
125132
'on_the_fly' => [
126-
'create_view' => backpack_url('entity/ajax/create'),
127-
'entity' => 'name_of_entity',
133+
'entity' => 'entity',
134+
'create_view => 'route/to/modal/html'
128135
]
129136
```
130137

131-
## Customization
138+
### Search logic
139+
140+
The "instant field" triggers the `ajaxIndex()` of the `EntityCrudController` where the field is defined and uses the fields `model` and `attribute` parameters to perform the search on the foreign model.
141+
142+
By adding `search_logic` to the field defintion you can implement your own searching behavior:
143+
144+
```
145+
'search_logic' => function($query, $searchTerm) {
146+
return $query->where('name', 'like', '%'.$searchTerm.'%')
147+
->whereActive()
148+
->whereSomethingElse();
149+
},
150+
```
151+
152+
Furthermore you can then use `attibute` to display enriched values in the dropdown by using an accessor on the model.
132153

133-
### Search behavior
154+
### Search data source
134155

135-
If you need a different search behavior just overwrite the `ajaxIndex()` method in your `EntityCrudController` and write your own search logic.
156+
If needed you are free to use the `data_source` attribute from the original field blades which come with Laravel Backpack. This is the URL that is triggered by the select2 field for searching.
136157

137158
### Request validation
138159

resources/views/fields/select2_from_ajax.blade.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
</select>
3838

3939
@if (isset($field['on_the_fly']))
40-
<button href="{{ $field['on_the_fly']['create_view'] }}"
40+
<button href="{{ $field['on_the_fly']['create_view'] ?? backpack_url($field['on_the_fly']['entity']).'/ajax/create' }}"
4141
type="button"
4242
class="btn btn-primary"
4343
data-toggle="modal"
@@ -113,13 +113,13 @@ class="btn btn-primary"
113113
allowClear: true,
114114
@endif
115115
ajax: {
116-
url: "{{ $field['data_source'] }}",
116+
url: "{{ $field['data_source'] ?? '/'.$crud->getRoute().'/ajax' }}",
117117
dataType: 'json',
118118
quietMillis: 250,
119119
data: function (params) {
120120
return {
121121
q: params.term, // search term
122-
searchkey: "{{ $field['attribute'] }}", // search key in database
122+
field: "{{ $field['name'] }}",
123123
page: params.page
124124
};
125125
},
@@ -128,9 +128,8 @@ class="btn btn-primary"
128128
129129
var result = {
130130
results: $.map(data.data, function (item) {
131-
textField = "{{ $field['attribute'] }}";
132131
return {
133-
text: item[textField],
132+
text: item["{{ $field['attribute'] }}"],
134133
id: item["{{ $connected_entity_key_name }}"]
135134
}
136135
}),

resources/views/fields/select2_from_ajax_multiple.blade.php

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</select>
3131

3232
@if (isset($field['on_the_fly']))
33-
<button href="{{ $field['on_the_fly']['create_view'] }}"
33+
<button href="{{ $field['on_the_fly']['create_view'] ?? backpack_url($field['on_the_fly']['entity']).'/ajax/create' }}"
3434
type="button"
3535
class="btn btn-primary"
3636
data-toggle="modal"
@@ -63,63 +63,65 @@ class="btn btn-primary"
6363

6464
{{-- FIELD CSS - will be loaded in the after_styles section --}}
6565
@push('crud_fields_styles')
66-
<!-- include select2 css-->
67-
<link href="{{ asset('vendor/adminlte/bower_components/select2/dist/css/select2.min.css') }}" rel="stylesheet" type="text/css" />
68-
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2-bootstrap-theme/0.1.0-beta.10/select2-bootstrap.min.css" rel="stylesheet" type="text/css" />
66+
<!-- include select2 css-->
67+
<link href="{{ asset('vendor/adminlte/bower_components/select2/dist/css/select2.min.css') }}" rel="stylesheet"
68+
type="text/css"/>
69+
<link
70+
href="https://cdnjs.cloudflare.com/ajax/libs/select2-bootstrap-theme/0.1.0-beta.10/select2-bootstrap.min.css"
71+
rel="stylesheet" type="text/css"/>
6972
@endpush
7073

7174
{{-- FIELD JS - will be loaded in the after_scripts section --}}
7275
@push('crud_fields_scripts')
73-
<!-- include select2 js-->
74-
<script src="{{ asset('vendor/adminlte/bower_components/select2/dist/js/select2.min.js') }}"></script>
76+
<!-- include select2 js-->
77+
<script src="{{ asset('vendor/adminlte/bower_components/select2/dist/js/select2.min.js') }}"></script>
7578
@endpush
7679

7780
@endif
7881

7982
<!-- include field specific select2 js-->
8083
@push('crud_fields_scripts')
81-
<script>
82-
jQuery(document).ready(function($) {
83-
// trigger select2 for each untriggered select2 box
84-
$("#select2_ajax_multiple_{{ $field['name'] }}").each(function (i, obj) {
85-
if (!$(obj).hasClass("select2-hidden-accessible"))
86-
{
87-
$(obj).select2({
88-
theme: 'bootstrap',
89-
multiple: true,
90-
placeholder: "{{ $field['placeholder'] }}",
91-
minimumInputLength: "{{ $field['minimum_input_length'] }}",
92-
ajax: {
93-
url: "{{ $field['data_source'] }}",
94-
dataType: 'json',
95-
quietMillis: 250,
96-
data: function (params) {
97-
return {
98-
q: params.term, // search term
99-
searchkey: "{{ $field['attribute'] }}", // search key in database
100-
page: params.page
101-
};
102-
},
103-
processResults: function (data, params) {
104-
params.page = params.page || 1;
84+
<script>
85+
jQuery(document).ready(function ($) {
86+
// trigger select2 for each untriggered select2 box
87+
$("#select2_ajax_multiple_{{ $field['name'] }}").each(function (i, obj) {
88+
if (!$(obj).hasClass("select2-hidden-accessible")) {
89+
$(obj).select2({
90+
theme: 'bootstrap',
91+
multiple: true,
92+
placeholder: "{{ $field['placeholder'] }}",
93+
minimumInputLength: "{{ $field['minimum_input_length'] }}",
94+
ajax: {
95+
url: "{{ $field['data_source'] ?? '/'.$crud->getRoute().'/ajax' }}",
96+
dataType: 'json',
97+
quietMillis: 250,
98+
data: function (params) {
99+
return {
100+
q: params.term, // search term
101+
field: "{{ $field['name'] }}",
102+
page: params.page
103+
};
104+
},
105+
processResults: function (data, params) {
106+
params.page = params.page || 1;
105107
106-
return {
107-
results: $.map(data.data, function (item) {
108-
return {
109-
text: item["{{$field['attribute']}}"],
110-
id: item["{{ $connected_entity_key_name }}"]
111-
}
112-
}),
113-
more: data.current_page < data.last_page
114-
};
108+
return {
109+
results: $.map(data.data, function (item) {
110+
return {
111+
text: item["{{ $field['attribute'] }}"],
112+
id: item["{{ $connected_entity_key_name }}"]
113+
}
114+
}),
115+
more: data.current_page < data.last_page
116+
};
117+
},
118+
cache: true
115119
},
116-
cache: true
117-
},
118-
});
119-
}
120+
});
121+
}
122+
});
120123
});
121-
});
122-
</script>
124+
</script>
123125
@endpush
124126
{{-- End of Extra CSS and JS --}}
125127
{{-- ########################################## --}}

src/Traits/CanBeCreatedOnTheFly.php renamed to src/Traits/InstantFields.php

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use Illuminate\Http\Request;
66

7-
trait CanBeCreatedOnTheFly
7+
trait InstantFields
88
{
99
/**
1010
* Returns the name of the on-the-fly entity. If more than one CRUD field provide on-the-fly you
@@ -28,6 +28,26 @@ public function setAjaxEntity(string $entity)
2828
$this->ajaxEntity = $entity;
2929
}
3030

31+
/**
32+
* Handles the incoming ajax requests by default
33+
* @param Request $request
34+
* @param null $create
35+
* @return mixed
36+
*
37+
*/
38+
public function handleAjaxRequest(Request $request, $create = null)
39+
{
40+
if ($create) {
41+
return $this->ajaxCreate();
42+
}
43+
44+
if (strtolower($request->method()) == 'post') {
45+
return $this->ajaxStore($request);
46+
}
47+
48+
return $this->ajaxIndex($request);
49+
}
50+
3151
/**
3252
* Provides the search algorithm for the select2 field. Overwrite it in
3353
* the EntityCrudController if you need some special functionalities
@@ -36,17 +56,16 @@ public function setAjaxEntity(string $entity)
3656
*/
3757
public function ajaxIndex(Request $request)
3858
{
39-
$search_term = $request->input('q');
40-
$search_key = $request->input('searchkey');
59+
$searchTerm = $request->input('q');
4160
$page = $request->input('page');
4261

43-
if ($search_term) {
44-
$results = $this->crud->query->where($search_key, 'LIKE', '%' . $search_term . '%')->paginate(10);
45-
} else {
46-
$results = $this->crud->query->paginate(10);
62+
$field = $this->crud->getFields(null)[$request->input('field')];
63+
64+
if (isset($field['search_logic']) && is_callable($field['search_logic'])) {
65+
return $field['search_logic']($field['model']::query(), $searchTerm)->paginate(10);
4766
}
4867

49-
return $results;
68+
return $field['model']::where($field['attribute'], 'LIKE', '%' . $searchTerm . '%')->paginate(10);
5069
}
5170

5271
/**

0 commit comments

Comments
 (0)