Giter Club home page Giter Club logo

demo.laravel-admin.org's People

Contributors

z-song avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

demo.laravel-admin.org's Issues

demo site not work

Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR)
Call to undefined method Encore\Admin\Widgets\Navbar::left()

How to use multipleselect by json

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'));

laravel-admin在回调函数的一个问题。

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请求,并没有直接跳转到目标地址。

http://localhost:8000/bankstatment_list/4164 post

http://localhost:8000/bankstatment_list/4164 get

How to use saving or saved method during click on delete button

Hi.

Description:

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?

Please help me. Thanks a lot.

  in menu select

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; }
    });
});

后台登录时怎么把 username 字段改为 email 字段验证?

我在 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 但是登录验证依然失败。。。
请求帮助。。。

在显示列表中

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';//定义主键这个就可以了。这是怎么回事?

Layout form

Is it possible to create one field in front of the other?

Extension not found

您好,我按照這篇 教程的 UserGender 來寫
可是出現 Method Encore\Admin\Grid::__toString() must not throw an exception, caught Error: Class 'App\Admin\Controllers\UserGender' not found
是不是我需要 publish 一些東西出來?

pipeline character in rules regex

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:
$form->text('test')->rules('required|regex:/^(AB|CD){2}[0-9]{4}$/');

this does not work:
$form->text('test')->rules(array('required', 'regex:/^(AB|CD){2}[0-9]{4}$/'));

Filter not working with a join eloquent in grid

Hi.

Description :

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.

Error :

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)

image

Tables :

branch_product table columns: id, branch_id, product_id
branch_product_stock table columns: id, stock

Controller :

`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'));
        });
    });
}

}`

Thans for your help.

Error opening or editing and deleting a post comment.

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'); });

Problem on custom grid tools

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.

Please Help Me !!

method "expand" in column object is in the demo , but can't find it in the files

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
image
, 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.

Cloud Storage and Local Storage

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?

create new menu

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

三级联动select时通过javascript修改select值时不能正确显示

通过调用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);
    });
};

Trait 'Encore\Admin\Controllers\HasResourceActions' not found

#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.*

$form->embeds validations

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...

安装完,点击Demo,页面报错

Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR)
Call to undefined method Encore\Admin\Widgets\Navbar::left()

是不是哪里操作不对。

引用插件openMap出现错误

环境: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.

How to filter with select which have more 60000 options

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 .

三级联动问题

联动的时候只有第一个select提交的是id,其他的提交的都是value,很费解啊。1.4版本

Radio filter is not working. Help

The following is my filter code.....
$grid->filter(function ($filter) {
$filter->disableIdFilter();
$filter->like('name');
$filter->equal('category')->radio([
'1' => 'Receive',
'0' => 'Issue',
]);
});

add SelectOrNew component

@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);

CSS, JS and images files are not accessible

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!

基于目前架构的Master-Detail实现方法分享

由于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>&nbsp;&nbsp;".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">&times;</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'=>'必要字段机构联系人不能为空!',]);
        });
    }

How to create custom widgets

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 ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.