z-song / demo.laravel-admin.org Goto Github PK
View Code? Open in Web Editor NEWSource code of official http://demo.laravel-admin.org website.
Source code of official http://demo.laravel-admin.org website.
我在 admin_users 表里增加了 email 字段:要使用 email 字段登录。
官方文档里有个自定义用户名
Laravel 默认使用 email 字段来认证。如果你想用其他字段认证,可以在 LoginController 里面定义一个 username 方法:
public function username()
{
return 'username';
}
但是 laravel-admin 登录中需要加在哪里?
我看 laravel-admin 框架里把 email 设置成了 username
在 vendor/encore/laravel-admin/src/Controllers/AuthController.php 文件的37行
public function postLogin(Request $request)
{
$credentials = $request->only(['username', 'password']);
$validator = Validator::make($credentials, [
'username' => 'required', 'password' => 'required',
]);
if ($validator->fails()) {
return Redirect::back()->withInput()->withErrors($validator);
}
if (Auth::guard('admin')->attempt($credentials)) {
admin_toastr(trans('admin.login_successful'));
return redirect()->intended(config('admin.route.prefix'));
}
return Redirect::back()->withInput()->withErrors(['username' => $this->getFailedLoginMessage()]);
}
我把 username 修改成了 email 但是登录验证依然失败。。。
请求帮助。。。
I need to add a "Save Draft" Button in my form.
So i added custom form widget.
How can I declare at /Admin/bootstrap.php ?
Hi.
I use a join eloquent in grid and then I use filter method. But the filter doesn't work.
I know that in the query below, product_id
= 1 is incorrect and branch_product
.product_id
= 1. But I don't know how to fix it in the filter method.
QueryException In Connection.php line 664 :
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'product_id' in where clause is ambiguous (SQL: select count(*) as aggregate from branch_product
inner join branch_product_stock
on branch_product_stock
.id
= branch_product
.id
where product_id
= 1)
branch_product table columns: id, branch_id, product_id
branch_product_stock table columns: id, stock
`class BranchProductController extends Controller
{
protected function grid()
{
return Admin::grid(BranchProduct::class, function (Grid $grid) {
$grid->model()
->join('branch_product_stock', 'branch_product_stock.id', '=', 'branch_product.id')
->select('branch_product.*', 'branch_product_stock.stock')
->orderBy('branch_product.branch_id')
->orderBy('branch_product.id');
$grid->column('id', 'ID')->sortable();
$grid->column('product.name', 'product')->sortable();
$grid->column('branch.name', 'branch')->sortable();
$grid->column('stock', 'stock')->sortable();
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('product_id', 'product')->select(Product::all()->pluck('name', 'id'));
$filter->equal('branch_id', 'branch')->select(Branch::all()->pluck('name', 'id'));
});
});
}
}`
由于master-detail表单形式在一对多和多对多的数据结构中常常使用.所以在不改动目前架构代码的情况下加了个外挂,希望z-song可以加入下个版本,如果能直接修改Form和Grid模块通过对Form加上属性Modal属性和相应方法,对Grid加上属性Detail等属性和相应方法,应该比外挂更容易实现,而且bug会少很多.
下面先说我的外挂组成:分别是ModalForm.php和DetailGrid.php两个外挂类型用来实现modal form和内嵌表格的主要功能和设置,其中ModalForm.php会引用客制化view:admin.extensions.modal_form
三个文件分别的存储位置是,其中{$project_dir}是你项目的目录地址
{$project_dir}/vendor/encore/laravel-admin/src/ModalForm.php
<?php
namespace Encore\Admin;
use Closure;
use Encore\Admin\Exception\Handler;
use Illuminate\Database\Eloquent\Model as EloquentModel;
use Encore\Admin\Form;
use Encore\Admin\Form\Tools;
use Encore\Admin\Form\Builder;
use Encore\Admin\Form\Field;
use Encore\Admin\Form\Field\File;
use Encore\Admin\Form\Row;
use Encore\Admin\Form\Tab;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Str;
use Illuminate\Validation\Validator;
use Spatie\EloquentSortable\Sortable;
use Symfony\Component\HttpFoundation\Response;
class ModalForm
{
public $form_name;
public $modal_form;
/**
* Create a new form instance.
*
* @param $model
* @param \Closure $callback
*/
protected function getModel($model)
{
if ($model instanceof EloquentModel) {
return $model;
}
if (is_string($model) && class_exists($model)) {
return $this->getModel(new $model());
}
throw new InvalidArgumentException("$model is not a valid model");
}
protected function formatFormName($form_name)
{
return 'Modal_Form_'.str_replace(' ','_',trim(ucwords(preg_replace('/([^(A-Za-z0-9)])+/',' ',$form_name))));
}
public function __construct($model, $callback,$form_name='default')
{
$this->form_name = $this->formatFormName($form_name);
$this->modal_form = new Form($this->getModel($model),$callback);
$this->modal_form->disableSubmit();
$this->modal_form->disableReset();
$this->modal_form->setView('admin.extensions.modal_form');
}
public function render()
{
$this->modal_form->builder()->getTools()->disableBackButton();
$this->modal_form->builder()->getTools()->disableListButton();
$render=preg_replace('/<form /i',"<form id='{$this->form_name}' ",$this->modal_form->render());
$render=str_replace('__MODAL_FORM_NAME__',"{$this->form_name}",$render);
$render=str_replace('__SUBMIT__',trans('admin.submit'),$render);
$render=str_replace('__RESET__',trans('admin.reset'),$render);
$admin_new=trans('admin.new');
$admin_create=trans('admin.create');
$admin_edit=trans('admin.edit');
$admin_delete=trans('admin.delete');
$admin_delete_confirm=trans('admin.delete_confirm');
$admin_cancel=trans('admin.cancel');
$admin_confirm=trans('admin.confirm');
$script=<<<SCRIPT
window.modal_form_mode='';
window.modal_form_id='';
window.modal_form='';
function registerLoadOptions()
{
var regEx=/(?:\\$\\(document\\)\\.on\\(\\'change\\',\\s*\\"\\.\\w+\\",\\s*function\\s*\\(\\)\\s*{\\s+)([^]*?)(?=\\.trigger)/g;
var html=$('body').html();
var match;
window.modal_load_options=[];
// console.log(window.modal_load_options);
while ((match = regEx.exec(html)) !== null)
{
var loadRegEx=/var target = \\$\\(this\\)\\.closest\\(\\'\\.fields-group\\'\\)\\.find\\(\\"\\.(\w+)\\"\\)/;
if (loadRegEx.exec(match[1])!== null)
{
var name=loadRegEx.exec(match[1])[1];
var loadUrlRegEx=/(?:\\$\\.get\\(\\")([^]*?)(?=\\"\\+this\\.value)/;
var loadUrl=match[1].match(loadUrlRegEx);
// console.log(loadUrlRegEx);
// console.log(loadUrl);
window.modal_load_options[name] = loadUrl[1];
}
}
// console.log(window.modal_load_options);
}
function selectOptions(key,value)
{
if (!Array.isArray(window.modal_load_options))
{
registerLoadOptions();
}
if (window.modal_load_options.hasOwnProperty(key))
{
var target = window.modal_form.find('select[name=' + key + ']');
if (value === '')
{
target.find("option").remove();
window.modal_form.find('[name=' + key + ']').val(value).trigger('change.select2');
}
else
{
$.when($.get(window.modal_load_options[key]+value, function (data) {
target.find("option").remove();
// console.log(data);
$(target).select2({
data: $.map(data, function (d) {
d.id = d.id;
d.text = d.text;
return d;
})
}).val(value).trigger('change.select2');
})).done(function(){
console.log('Options:['+key+']='+value+'Loaded!');
});
}
return;
}
console.log('Form:['+window.modal_form.attr('id')+'] Options:['+key+']='+value+'Loaded!');
window.modal_form.find('[name=' + key + ']').val(value).trigger('change.select2');
}
function domEquipment(key,value)
{
var dom = window.modal_form.find('[name=' + key + ']');
if (dom.is('select'))
{
selectOptions(key,value);
}
else
{
switch (dom.attr("type"))
{
case "text":
case "hidden":
case "textarea":
dom.val(value);
break;
case "radio":
case "checkbox":
dom.val(value);
dom.each(function()
{
if ($(this).attr('value') == value)
{
$(this).attr("checked", value);
}
});
break;
}
}
}
function populateForm(data)
{
console.log(data);
$.each(JSON.parse(data), function(key, value)
{
domEquipment(key,value);
});
}
function apiModalEditData()
{
$.get(window.modal_form.attr('action'), function (data)
{
data=data.replace(/^\[/,'').replace(/\]$/,'');
populateForm(data);
});
}
function resetError()
{
window.modal_form.find('.form-group').removeClass('has-error');
window.modal_form.find('label[for=inputError]').remove();
}
function resetModalForm()
{
window.modal_form.find('input:text, input:password, textarea').val('').trigger('change');
window.modal_form.find('select').each(function(){
console.log($(this).attr('name'));
selectOptions($(this).attr('name'),'');
$(this).val('').trigger('change.select2');
});
window.modal_form.find('input:radio, input:checkbox').prop('checked', false).trigger('change');
window.modal_form.serializeArray().forEach(function(element){
console.log('['+element.name+']="'+element.value+'"');
});
// window.modal_form.attr('action','');
resetError();
}
$('.grid-row-edit .fa-edit').unbind('click').click(function() {
var id = $(this).data('id');
var apiUrl = $(this).data('url')+'/'+id+'?_ajax=1';
window.modal_form = $('#'+$(this).data('form'));
window.modal_form.closest('.modal').find('.modal-title').text("{$admin_edit}");
window.modal_form_mode='edit';
resetModalForm();
window.modal_form.attr('action',apiUrl);
console.log(window.modal_form.attr('action'));
apiModalEditData();
window.modal_form.attr('action',$(this).data('url')+'/'+id);
});
$('.grid-row-create').unbind('click').click(function() {
var data=$(this).find('.fa-save');
window.modal_form = $('#'+data.data('form'));
var apiUrl = data.data('url');
console.log(apiUrl);
window.modal_form.closest('.modal').find('.modal-title').text("{$admin_new}");
window.modal_form_mode='create';
resetModalForm();
window.modal_form.attr('action',apiUrl);
});
$('.grid-row-delete .fa-trash').unbind('click').click(function() {
var id = $(this).data('id');
var apiUrl = $(this).data('url')+'/'+id;
window.modal_form = $('#'+$(this).data('form'));
swal({
title: "{$admin_delete_confirm}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{$admin_confirm}",
closeOnConfirm: false,
cancelButtonText: "{$admin_cancel}"
},
function(){
$.ajax({
method: 'post',
url: apiUrl,
data: {
_method:'delete',
_token:LA.token,
},
success: function (data) {
$.pjax.reload('#pjax-container');
if (typeof data === 'object') {
if (data.status) {
swal(data.message, '', 'success');
} else {
swal(data.message, '', 'error');
}
}
}
});
});
window.modal_form.closest('.modal').modal('hide');
});
$('.modal_form_button').unbind('click').click(function()
{
console.log($(this));
type=$(this).data('type');
window.modal_form=$('#'+$(this).data('form'));
switch(type)
{
case 'reset':
resetButtonClick();
break;
case 'submit':
submitButtonClick();
}
});
function submitButtonClick(){
apiUrl=window.modal_form.attr('action');
fields={};
window.modal_form.serializeArray().forEach(function(element){
fields[element.name]=element.value;
});
if (window.modal_form_mode=='edit')
{
fields['_method']='PUT';
}
fields['_ajax']=1;
console.log(fields);
console.log(apiUrl);
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': LA.token
}
});
$.ajax({
url: apiUrl,
method: (window.modal_form_mode=='edit')?'put':'post',
data: fields,
success: function(data)
{
console.log(data);
resetError();
if (typeof data === 'object')
{
if (data.status)
{
window.modal_form.closest('.modal').modal('hide');
$.pjax.reload('#pjax-container');
swal(data.message, '', 'success');
}
else
{
for (var key in data.message)
{
if (data.message.hasOwnProperty(key))
{
window.modal_form.find('[name='+key+']').closest('.form-group').addClass('has-error');
window.modal_form.find('[name='+key+']').closest('.col-sm-8').append(data.message[key]);
console.log(key+':');
console.log(data.message[key]);
}
};
//swal(data.message, '', 'error');
}
}
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr);
console.log(thrownError);
swal("Internal Error!\\n"+xhr.status+':'+xhr.statusText, '', 'error');
}
});
}
function resetButtonClick(){
console.log(window.modal_form_mode);
var apiUrl=window.modal_form.attr('action');
resetModalForm();
if (window.modal_form_mode=='edit')
{
window.modal_form.attr('action',apiUrl+'?_ajax=1');
console.log(window.modal_form.attr('action'));
apiModalEditData();
window.modal_form.attr('action',apiUrl);
}
}
SCRIPT;
Admin::script($script);
return $render;
}
public function __toString()
{
return $this->render();
}
}
{$project_dir}/vendor/encore/laravel-admin/src/DetailGrid.php
<?php
namespace Encore\Admin;
use Closure;
use Encore\Admin\Grid;
use Encore\Admin\Grid\Tools\AbstractTool;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Support\Facades\Input;
class DetailGridCreateButton extends AbstractTool
{
/**
* Create a new CreateButton instance.
*
* @param Grid $grid
*/
public function __construct(Grid $grid)
{
$this->grid = $grid;
}
/**
* Render CreateButton.
*
* @return string
*/
public function render()
{
return "<div class='btn-group pull-right' style='margin-right: 10px'><a href='' class='btn btn-sm btn-success grid-row-create' data-toggle='modal' data-target='#Main___MODAL_FORM_NAME__'><i class='fa fa-save' data-type='create' data-url='__URL__' data-form='__MODAL_FORM_NAME__'></i> ".trans('admin.new')."</a></div>";
}
}
class DetailGrid
{
protected $form_name;
public $grid;
protected function accessProtected($obj, $prop)
{
$reflection = new \ReflectionClass($obj);
$property = $reflection->getProperty($prop);
$property->setAccessible(true);
return $property->getValue($obj);
}
public function getModel($model)
{
if ($model instanceof Eloquent) {
return $model;
}
if (is_string($model) && class_exists($model)) {
return $this->getModel(new $model());
}
throw new InvalidArgumentException("{$model} is not a valid model");
}
protected function formatFormName($form_name)
{
return 'Modal_Form_'.str_replace(' ','_',trim(ucwords(preg_replace('/([^(A-Za-z0-9)])+/',' ',$form_name))));
}
public function __construct(Eloquent $model, Closure $callback, $form_name='default')
{
$this->form_name= $this->formatFormName($form_name);
$this->grid = new Grid($model,$callback);
$this->grid->disableCreation();
}
public function setFormName($form_name)
{
$this->form_name = $this->formatFormName($form_name);
}
public function render()
{
//dd($this->grid);
$this->grid->tools->prepend(new DetailGridCreateButton($this->grid));
//dd($this->grid);
$render=$this->grid->render();
$render=str_replace('__MODAL_FORM_NAME__',"{$this->form_name}",$render);
$render=str_replace('__URL__',"{$this->grid->resource()}",$render);
//dd($render);
return $render;
}
public function __toString()
{
return $this->render();
}
}
{$project_dir}/resources/views/admin/extensions/modal_form.blade.php
<div class="modal" id="Main___MODAL_FORM_NAME__" tabindex="-1" role="dialog" aria-labelledby="__MODAL_FORM_NAME__Label" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header text-center">
<button type="button" class="close" data-dismiss="#Main___MODAL_FORM_NAME__" aria-label="Close" >
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title w-100 font-weight-bold">{{ $form->title() }}</h4>
</div>
<div class="modal-body mx-3">
<!-- /.box-header -->
<!-- form start -->
@if($form->hasRows())
{!! $form->open() !!}
@else
{!! $form->open(['class' => "form-horizontal ModalForm"]) !!}
@endif
<div class="box-body">
@if(!$tabObj->isEmpty())
@include('admin::form.tab', compact('tabObj'))
@else
<div class="fields-group">
@if($form->hasRows())
@foreach($form->getRows() as $row)
{!! $row->render() !!}
@endforeach
@else
@foreach($form->fields() as $field)
{!! $field->render() !!}
@endforeach
@endif
</div>
@endif
</div>
<!-- /.box-body -->
<div class="box-footer">
@if( ! $form->isMode(\Encore\Admin\Form\Builder::MODE_VIEW) || ! $form->option('enableSubmit'))
<input type="hidden" name="_token" value="{{ csrf_token() }}">
@endif
<div class="col-md-{{$width['label']}}">
</div>
<div class="col-md-{{$width['field']}}">
<div class="btn-group pull-right">
<button type="button" class="btn btn-info pull-right modal_form_button" data-type="submit" data-form="__MODAL_FORM_NAME__" data-loading-text="<i class='fa fa-spinner fa-spin '></i> __SUBMIT__">__SUBMIT__</button>
</div>
<div class="btn-group pull-left">
<button type="button" class="btn btn-warning modal_form_button" data-type="reset" data-form="__MODAL_FORM_NAME__">__RESET__</button>
</div>
</div>
@foreach($form->getHiddenFields() as $hiddenField)
{!! $hiddenField->render() !!}
@endforeach
</div>
<!-- /.box-footer -->
{!! $form->close() !!}
</div>
</div>
</div>
</div>
<!-- /.modal -->
然后先创建DetailGrid所对应的Controller
比如说,你的供应商对应多个站点,你就先建一个SiteController,实现功能是创建一个针对某个供应商的CRUD页面,注意要设好你的rules和对应的messages,因为之后的ModalForm校验就是通过这个Controller的.然后引入ModalForm的trait替换掉原来的ModelForm的trait.这个新的trait文件主要是来处理接受从ModalForm和DetailGrid发起的CRUD事件请求,同时兼顾目前Controller的网页请求的完整性.
这个ModalForm.php的trait文件存放位置是:
{$project_dir}/app/Admin/Controllers/Extensions/includes/ModalForm.php
<?php
namespace App\Admin\Controllers\Extensions\includes;
trait ModalForm
{
protected function accessProtected($obj, $prop)
{
$reflection = new \ReflectionClass($obj);
$property = $reflection->getProperty($prop);
$property->setAccessible(true);
return $property->getValue($obj);
}
public function ajaxValidators($form)
{
$rules=[];
$messages=[];
foreach ($form->builder()->fields() as $field)
{
$rules[$this->accessProtected($field,'id')]=$this->accessProtected($field,'rules');
foreach($this->accessProtected($field,'validationMessages') as $rule=>$message)
{
$messages[$this->accessProtected($field,'id').'.'.$rule]=$message;
}
}
$validator = \Validator::make(\Illuminate\Support\Facades\Input::all(),$rules,$messages);
if ($validator->fails())
{
$messages=[];
foreach($validator->getMessageBag()->toArray() as $key=>$errors)
{
$messages[$key]='';
foreach($errors as $error)
{
$messages[$key].="<label class='control-label' for='inputError'><i class='fa fa-times-circle-o'></i> {$error}<br/></label>";
}
}
return response([
'status' => false,
'message' => $messages,
]);
}
return false;
}
/**
* Display the specified resource.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function show($id)
{
if (array_key_exists('_ajax',\Illuminate\Support\Facades\Input::all()))
{
$model=$this->form()->model();
$ret=$model->where($model->getKeyName(),'=',$id)->first();
return $ret?json_encode($ret):'{}';
}
return $this->edit($id);
}
/**
* Update the specified resource in storage.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function update($id)
{
if (array_key_exists('_ajax',\Illuminate\Support\Facades\Input::all()))
{
$form=$this->form($id);
if ($response=$this->ajaxValidators($form))
{
return $response;
}
$this->form($id)->update($id);
return response([
'status' => true,
'message' => trans('admin.update_succeeded'),
]);
}
return $this->form($id)->update($id);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
if ($this->form()->destroy($id)) {
return response()->json([
'status' => true,
'message' => trans('admin.delete_succeeded'),
]);
} else {
return response()->json([
'status' => false,
'message' => trans('admin.delete_failed'),
]);
}
}
/**
* Store a newly created resource in storage.
*
* @return \Illuminate\Http\Response
*/
public function store()
{
if (array_key_exists('_ajax',\Illuminate\Support\Facades\Input::all()))
{
$form=$this->form();
if ($response=$this->ajaxValidators($form))
{
return $response;
}
$this->form()->store();
return response([
'status' => true,
'message' => trans('admin.update_succeeded'),
]);
}
return $this->form()->store();
}
}
然后创建你的Master-Detail表单,由于必须要有Master的记录才可以进行Detail记录的创建,所以我们主要是修改edit的方法,同时加上两个新的函数detailgrid和modalform.示例代码如下:
对edit方法的修改
public function edit($id)
{
return Admin::content(function (Content $content) use ($id) {
$content->header('服务机构信息');
$content->description('服务机构信息维护');
$content->body($this->form($id)->edit($id).$this->detailGrid($id).$this->modalForm($id));
});
}
同时会应用到下面的一个include文件,没办法写外挂都这样!!!
重构Grid行Action按钮的代码
{$project_dir}/app/Admin/Controllers/Extensions/includes/DetailGridActions.php
<?php
$actions->disableEdit();
$actions->disableDelete();
$actions->prepend("<a href='javascript:void(0);' class='grid-row-delete'><i class='fa fa-trash' data-url='{$actions->getResource()}' data-form='__MODAL_FORM_NAME__' data-id='{$actions->getKey()}'></i></a>\n");
$actions->prepend("<a href='javascript:void(0);'' data-toggle='modal' data-target='#Main___MODAL_FORM_NAME__' class='grid-row-edit'><i class='fa fa-edit' data-url='{$actions->getResource()}' data-form='__MODAL_FORM_NAME__' data-id='{$actions->getKey()}'></i></a>\n");
?>
新增的两个方法,分别对应DetailGrid和ModalForm
protected function detailGrid($pid)
{
return new DetailGrid(new BackendAssitListViewSites, function (Grid $grid) use($pid){
$grid->resource(admin_base_path('/site'));
$grid->model()->where('supp_id','=',$pid);
$grid->supp_name('服务机构')->sortable();
$grid->province_name('省')->sortable();
$grid->city_name('市')->sortable();
$grid->area_name('区')->sortable();
$grid->site_name('站点名称')->sortable();
$grid->site_addr('站点地址')->sortable();
$grid->contact_info('联系人信息');
/****
***** 下面的设置非常重要是告诉用来重构调用ModalForm的编辑和删除按钮!!!
*****/
$grid->actions(function ($actions){
include(__DIR__.'/Extensions/includes/DetailGridActions.php');
});
});
}
protected function modalForm($pid=null)
{
return new ModalForm(new \App\Models\Site, function (Form $form) use($pid)
{
/****
***** 下面的设置非常重要是告诉AJAX从这个Resource地址获取CRUD操作!!!
*****/
$form->resource(admin_base_path('/site'));
/****
***** 下面两行的设置非常重要是告诉AJAX从对应的子表主键和父表主键!!!
*****/
$form->hidden('site_id');
$form->hidden('supp_id', '服务机构')->value($pid);
/****
***** 其实下面的代码可以从对应的Controler拷贝过来,而且可以移除rules
*****/
$form->text('site_name','站点名称')
->rules('required',
['required'=>'必要字段站点名称不能为空!',
'unique' =>'出现重复站点名称!']);
$form->select('province', '省')
->options(\App\Models\AreaCode::provinces()->pluck('area_name','area_id'))
->load('city',admin_base_path('/api/cities'))
->rules('required',['required'=>'必要字段不能为空!']);
$form->select('city', '市')
->load('area',admin_base_path('/api/areas'))
->rules('required',['required'=>'必要字段不能为空!'])
->options(function($id)
{
return \App\Models\AreaCode::cities($id)->pluck('area_name','area_id');
});
$form->select('area', '区')
->rules('required',['required'=>'必要字段不能为空!'])
->options(function($id)
{
return \App\Models\AreaCode::areas($id)->pluck('area_name','area_id');
});
$form->text('site_addr','站点地址')
->rules('required',['required'=>'必要字段不能为空!']);
$form->select('contact_id','机构联系人')
->options(\App\Models\Contact::contactInfo()->pluck('contact_info','contact_id'))
->rules('required',['required'=>'必要字段机构联系人不能为空!',]);
});
}
Hi
I'm wanting to pass an id to another page by filtering according to the passed ID Ex:
area - Main table
id
name
type_id
area_type - secondary table
id
area_id
name
I'm looking for an example, when clicking on an "area" action I can pass the area id and filter "area_type" from this filter. The example I found closest in the demo was the Post and comment.
when opening a post in the demo example through the link below. When you click on any view action, edit or delete the comment, it presents an error, does not open the form nor excludes.
https://demo.laravel-admin.org/posts/1/edit
this error.
https://demo.laravel-admin.org/demo/post-comments/38
I accessed the post controller, but I did not identify the error.
https://github.com/z-song/demo.laravel-admin.org/blob/master/app/Admin/Controllers/PostController.php
Anyone have any tips, thanks?
Area grid - PostController
$grid->actions(function (Grid\Displayers\Actions $actions) { $actions->append('<a href="area-categoria/'.$actions->getKey().'"><i class="fa fa-paper-plane"></i></a>'); });
Area type grid - PostCommentController
$grid->filter(function ($filter) { $filter->like('content'); });
I has a controller but when i get a user does not work:
$user = Admin::user();
error:
Class 'App\Admin\Controllers\Admin' not found
why ?
本地测试也一样,save()返回true 但是数据库没有被更新
@langeuh commented on Fri May 26 2017
select from existing values for a certain column or add a new one.
if no options are given, options are filled in automatically using the unique values for the given column. By default the selection can be cleared and an empty value is prepended. You can turn it off by calling allowClear(false) on the field.
e.g.
$form->selectOrNew('salutation’);
or specify options yourself
$form->selectOrNew('salutation')
->options([
1 => ‘sir’,
2 => ‘misses’,
])
->rules('required')
->allowClear(false);
allowClear
there is method to set wether you can clear the selection or not:
$form->selectOrNew('salutation’)->allowClear();
inside a nestedForm you’ll need to dataModel() to specify on which model to get the default options from (can't seem to find the related model. Please change it if possible)
$form->selectOrNew('city')
->rules('max:50|string')
->attribute('maxlength', 50)
->dataModel(Address::class);
Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR)
Call to undefined method Encore\Admin\Widgets\Navbar::left()
I have installed the admin in Laravel by command lines. I am able to access admin, log into the admin but assets files are not accessible. CSS, JS, and images are displaying blank. Please check the URL http://billing.sbware.com/css/owl.carousel.css.
My URL is http://billing.sbware.com/.
I have set up the APP URL (http://billing.sbware.com) and DB details in the .env file. All Files permission is 0664 and folder permission is 0775. But still, I am getting this issue.
Can you please suggest me regarding this issue.
Looking forward to hearing from you soon!
Thanking You!
I call an api for select field, then when the user select the item from the list , i need to change other fields based on the selected data.
Hello,
Form validation in embeds seems does not works.
$form->embeds('price', 'Device price list', function ($form) {
$form
->text('price', $r->vendor->title . '/' . $r->title)
->rules('integer');
});
I can save text...
add new permission successful but did not save to table? LOG: Invalid route action: [Closure].
Call to undefined method Encore\Admin\Widgets\Navbar::left()
通过调用apiModalEditData(apiUrl)正确拿到数据的json,然后在将对应值填入表单时,只有第一层省份信息是正确的.调试过程发现联动的$.get()出现时延,导致下层数据出来后,被上层数据覆盖.而且修改值的顺序也是省、市、区.下面是用来将json数据填写表单时用到的script
function domEquipment(key,value)
{
var dom = $('[name=' + key + ']');
console.log('[name=' + key + ']='+value);
if (dom.is('select'))
{
dom.val(value).trigger('change');
$("option", dom).each(function()
{
if (this.value == value)
{
this.selected = true;
}
else
{
this.selected = false;
}
});
dom.val(value).trigger('change');
console.log(dom);
}
else
{
switch (dom.attr("type"))
{
case "text":
case "hidden":
case "textarea":
dom.val(value).trigger('change');
break;
case "radio":
case "checkbox":
dom.val(value).trigger('change');
dom.each(function()
{
if ($(this).attr('value') == value)
{
$(this).attr("checked", value);
}
});
break;
}
}
};
function populateForm(frm, data)
{
$.each(JSON.parse(data), function(key, value)
{
domEquipment(key,value);
});
};
function apiModalEditData(apiUrl)
{
$.get(apiUrl, function (data)
{
data=data.replace('[','').replace(']','');
populateForm('.modal_form',data);
});
};
如题
您好,我按照這篇 教程的 UserGender 來寫
可是出現 Method Encore\Admin\Grid::__toString() must not throw an exception, caught Error: Class 'App\Admin\Controllers\UserGender' not found
是不是我需要 publish 一些東西出來?
使用 Encore\Admin\Widgets\Form
类快速构建表单,请问图片怎么显示出来呢?如何填充图片的默认值?
I want to use both local storage and cloud storage. Some images will upload to cloud and some will upload to local. Is there any tips for upload to specific disk?
in the demo inside the user grid , there is a column with the feature to expand and view a table with the profile information inside it , I tried to use the same code and it is giving me a null cell in the column
, and I can't find any method inside the column.php file called "expand" . was this functionality removed ?
if it was what can I do to mimic the same behavior without using the expand method.
I need to filter with more than 60000 options select.
There have only two ways to filter with select by documentation.
`$filter->equal('column')->select(['key' => 'value'...]);
// Or from the api to obtain data, api format reference model-form select
component
$filter->equal('column')->select('api/users');`
Both ways can't load 60000 options .
$grid->actions(function ($actions) {
$actions->disableView();
});
是这个吗?
protected $connection = 'mysql';
protected $table ='order';
protected $primaryKey = 'order_id';//定义主键
// public $timestamps = false;//类似addtime updatetime
public $timestamps = false;
如果我在model中设置主键的话,
在grid中:
$grid->order_id('订单号');
主键order_id拿不到任何信息,屏蔽掉protected $primaryKey = 'order_id';//定义主键这个就可以了。这是怎么回事?
我发现http://demo.laravel-admin.org/media 这个里面的代码没找到
Hi.
I want to store and display json data by multipleselect.
How do I do?
for example data on database : ["2","4","9"]
$form->multipleSelect('categories', 'cat')->options(Category::all()->pluck('name', 'id'));
Can you show me composer.json for Laravel 5.4?
nothing saved!
using pipeline character ( | ) in rules regex validation will break the rules, following Laravel 5.5 doc using array instead of one line is not working
Eg.
this will break:
this does not work:
Hi.
I use laravel-admin interface builder in my project. I delete rows without doing anything. I just click on the delete button, and then the row is automatically deleted from the database. It's excellent :)
But I want to use the saving or saved method during deletion. I don't know how to do it :(
Also in a form I disabled reset button and enable delete button and I use form edit submit button, too. I add $form->enableDelete();
and $form->disableReset();
to my code. In this case, the deletion operation is done automatically, too.
Now, how can I use saving or saved method?
使用 Encore\Admin\Widgets\Form
表单组件,怎么扩展富文本编辑器呢?
But I think, you know about this. I like your panel but It doesn't gives flexibility, as for example SeleepingOwl :(
Hi,
I have a need to split one form into two horizental fieldsets.
im not taling about 2 fielfd in a row, im talking about real fieldset.
Something like:
https://i.imgur.com/wk2lbZ6.png
Is it possible?
Thanks
Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR)
Call to undefined method Encore\Admin\Widgets\Navbar::left()
是不是哪里操作不对。
环境:os.x 1.13.2, chrome, laravel-admin-1.5.x dev
我引用了示例代码中的openMap.php然后按照UserController.php的使用方法,同时在bootstrap.php中添加openMap
加载代码,结果在我的网站上出现了下面的错误,并且界面中不显示和demo中位置按钮,请问该如何解决?
A parser-blocking, cross site (i.e. different eTLD+1) script,
http://open.map.qq.com/apifiles/2/4/85/main.js, is invoked via document.write.
The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity.
If blocked in this page load, it will be confirmed in a subsequent console message.
See https://www.chromestatus.com/feature/5718547946799104 for more details.
请问,这三个范围组件dateRange datetimeRange, timeRange 如何像当个组件一样设置默认值呢?
e.g.:
$form->date("created_time", '创建日期')->default("2018-04-20");
Editing of nested menus became hell: http://joxi.ru/brRKqyIQ0EKDm1
I am just started to explore Laravel and used your solution as admin panel (Cool-Cool-Cool).
Maybe it will be good to add the next js:
$(document).ready(function() {
$('.select2-hidden-accessible').select2({
escapeMarkup: function (text) { return text; }
});
});
联动的时候只有第一个select提交的是id,其他的提交的都是value,很费解啊。1.4版本
Is it possible to create one field in front of the other?
Filter not working when we search Foo as foo
Hi.
I use two grid on one page. and use custom grid tools on each gird. I use the code of below on the first grid tools:
$grid->tools(function (Grid\Tools $tools) { $tools->batch(function (Grid\Tools\BatchActions $batch) { $batch->disableDelete(); foreach (Driver::active()->get() as $d) { $batch->add("$d->name", new SetDriver($d->id)); } }); });
and second gird:
$grid->tools(function (Grid\Tools $tools) { $tools->batch(function (Grid\Tools\BatchActions $batch) { $batch->disableDelete(); $batch->add("Unset driver", new UnsetDriver(0)); $batch->add("done", new OrdersSetDone(0)); }); });
When I click on first grid tools all of things is OK. But I click on second grid tools (for example Unset driver) Both of the UnsetDriver() and SetDriver() are executed.
The following is my filter code.....
$grid->filter(function ($filter) {
$filter->disableIdFilter();
$filter->like('name');
$filter->equal('category')->radio([
'1' => 'Receive',
'0' => 'Issue',
]);
});
laravel-admin在回调函数的一个问题。
在edit页面,调用form->saving回调函数时,遇到一个问题:
如果在函数里用了dump方法来获取提交的数据后,后续再用redirect,并不能正常重定向目标地址。
$form->saving(function (Form $form){
$account_order_id = $form->model()->account_order_id;
$new_status = dump($form->status);
.......
});
return redirect('bankstatment_list/')->with(compact('success'));
}
利用F12调试发现,发起post请求后,系统又发起了一个当前页面的get请求,并没有直接跳转到目标地址。
QueryException In Connection.php line 664 :
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'menu_id' cannot be null (SQL: insert into admin_role_menu
(menu_id
, role_id
) values (, 1))
Expand Collapse
#35 提到这个问题,作者回复:
这个demo依赖的laravel-admin版本是1.5.x-dev, 1.5.x-dev对应master分支
看了下1.5.x-dev发布时间:2018-05-06 10:10 UTC,并不是maser分支?
而HasResourceActions创建时间也是在八月份 。
切换到1.5.19会报其他错误,切换到dev-master没问题,但extensions依赖1.5.*
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.