前言
上一节,我们对 article 和 tag 的多对多关系进行了代码上的实现。本节,继续上节,让我们如何在 UI 上实现对 tag 的选择。
说明
开发环境:Windows 7
Laravel 版本: 5+
IDE: Phpstorm
上节课,我们以文章的 tag 为例子,将 article 和 tag 作为多对多的事例进行讲解,并且实现了文章和标签的绑定。这节课,我们看看在页面上,也就是 UI 上怎么实现对 tag 的选取。
什么是 select 控件?不知道啊?不知道的话看一下下面的效果就知道了。
打开 form.blade.php ,在 published_at 下面添加一个 form 标签:
{!! Form::label('tags','Tags:') !!}{!! Form::select('tags',['default'],null,['class'=>'form-control']) !!}
其实这些东西,以前都多少有些子集,具体不需要怎么多讲,你可以看看效果就明白每个参数的意义。这个 class 是 bootstrap 定义的类型。然后打开服务器,访问一下 localhost:8888/articles/create ,看到了嘛,在 publish on 下面多了一个 tags 和一个可以选择的控件。
既然是选择,那就需要多个选项。对于我们来说,就是多个 tag 。改一下代码,添加一个关键字:
{!! Form::label('tags','Tags:') !!}{!! Form::select('tags',['default'],null,['class'=>'form-control','multiple']) !!}
现在虽然有了变化,但是我们的 tag 是静态的,写死的。要是能穿第一个 $tagList 或者 $tags(下面统称为 $tags) 就好了。
那既然想获取这个 $tags ,想象这个逻辑,这个 $tags 是什么时候被传递到这个创建的页面的?那也就是当我们访问 localhost:8888/articles/create 的时候,会把 $tags 一同携带过来,如此,我们才能把 $tags 传递到这个 Form 中,对吧?
下面看怎么搞。
打开 ArticlesController.php ,找到 create() 方法,这里就是我们如何访问 localhost:8888/articles/create 的。
在 create() 方法里加入如下代码:
public function create(){ $tags=\App\Tag::lists('name'); return view('articles.create',compact('tags'));}
是的,我们就是通过那一句来获取 tag 的 name (名称)的。不过现在,我们的 tag 列表里只有一个 tag ,就是上节创建的,我们需要再创建几个 tag 才能看出效果。
打开 Tag.php,在 Tag 类中添加如下数组:
protected $fillable = [ 'name'];
把 name 添加到 $fillable 数组中,防止 MassAssignmentException 。 接下来切换到 tinker 模式: php artisan tinker :
>>> \App\Tag::create(['name'=>'work']);=> App\Tag {#656 name: "work", updated_at: "2016-05-01 14:02:13", created_at: "2016-05-01 14:02:13", id: 2,}>>> \App\Tag::create(['name'=>'coding']);=> App\Tag {#655 name: "coding", updated_at: "2016-05-01 14:03:50", created_at: "2016-05-01 14:03:50", id: 3,}>>> \App\Tag::create(['name'=>'life']); => App\Tag {#645 name: "life", updated_at: "2016-05-01 14:04:29", created_at: "2016-05-01 14:04:29", id: 4,}>>> \App\Tag::lists('name');=> Illuminate\Support\Collection {#653 all: [ "personal", "work", "coding", "life", ],}
哈,通过 \App\Tag::lists(‘name’); 可以看到我们的 tag name list 。目前 list 是通过下标的方式来获取值的,比如: $tags[2] 取到的值就是 ‘coding’;如果我想通过 tag 名称来获取 tag 呢?比如: $tags[‘coding’] 取到的值就是 ‘coding’。接着看:
>>> \App\Tag::lists('name','name');=> Illuminate\Support\Collection {#664 all: [ "personal" => "personal", "work" => "work", "coding" => "coding", "life" => "life", ],}
不错,改一下吧。打开 ArticlesController.php 把 create() 方法改成如下:
public function create(){ $tags=\App\Tag::lists('name','name'); return view('articles.create',compact('tags'));}
完工。看下效果吧。访问 localhost:8888/articles/create 。不错~有效果,可以选择了,可以通过 shift 键进行多选哦。
选择之后,我们要创建文章的时候,我们所提交的 tag 到底有多少,怎么查看一下?
打开 ArticlesController.php ,找到 store() 方法,因为这个方法是用来存储文章的。找到之后,我们在该方法中加入一句:
public function store(ArticleRequest $request){ dd($request->input('tags')); $article = new Article($request->all()); Auth::user()->articles()->create($article); return redirect('articles')->with([ 'flash_message'=>'Your article has been created!', 'flash_message_important'=>true]);}
加一句 dd(),当你通过 shift 把标签全都选中的时候,提交创建文章后,会发现只有一个 tag 值。呃?不是选了四个么。回到 form.blade.php ,修改一下这里就可以解决:
{!! Form::select('tags[]',$tags,null,['class'=>'form-control','multiple']) !!}
把 tags 改成 tags[] 后,我们传递的便是数组,而不是首位值。
好了,回到 ArticlesControllerphp 的 store() 方法中,把 dd 注释掉。目前的情况是,我们获取到了所有选中的 tags ,下一步,就该将这些 tags 与 文章进行绑定了。这一动作和上一节的绑定动作类似。
但是上一节我们将 article 与 tag 进行绑定的时候,用到的是 tag 的 id ,而不是 tag 的 name。那当初我们为什么要获取 name (为了效果。。。),直接获取 id 不就完了?是的。
在 ArticlesController.php 中找到 create() 方法,修改如下:
public function create(){ $tags=\App\Tag::lists('name','id'); return view('articles.create',compact('tags'));}
这样就可以了,不用试了,真的可以了。
回到 store() 方法中,写下如下代码进行 article 与 tag id们进行绑定:
public function store(ArticleRequest $request){ $article = Auth::user()->articles()->create($request->all()); $article->tags()->attach($request->input('tags')); return redirect('articles')->with([ 'flash_message'=>'Your article has been created!', 'flash_message_important'=>true]);}
第一句,获取到 article 表单中的值,第二句,获取到表单中 tags 的 id 们,重要的就是第三句,将 文章与其标签进行绑定,通过标签的 id 。
我们去试一试。文章是发表成功了,看看数据库里吧,切换到 tinker 模式:
>>> $article = App\Article::find(10);=> App\Article {#659 id: "10", user_id: "1", created_at: "2016-05-01 15:26:08", updated_at: "2016-05-01 15:26:08", title: "asd", body: "asdasdasdasd", published_at: "2016-05-09 00:00:00", }>>> $article->tags->toArray();=> [ [ "id" => 2, "name" => "work", "created_at" => "2016-05-01 14:02:13", "updated_at" => "2016-05-01 14:02:13", "pivot" => [ "article_id" => "10", "tag_id" => "2", "created_at" => "2016-05-01 15:26:08", "updated_at" => "2016-05-01 15:26:08", ], ], [ "id" => 3, "name" => "coding", "created_at" => "2016-05-01 14:03:50", "updated_at" => "2016-05-01 14:03:50", "pivot" => [ "article_id" => "10", "tag_id" => "3", "created_at" => "2016-05-01 15:26:08", "updated_at" => "2016-05-01 15:26:08", ], ], ]
嗯,还是没问题的。两个标签。
文章展示的时候,一般在其下方会有文章的标签,下面我们就实现这个。打开 show.blade.php ,在 body div 下面再创建一个标签:
<h5>Tags:</h5><ul> @foreach ($article->tagsas $tag) <li> {{ $tag->name }} </li> @endforeach</ul>
刷新页面看一下效果吧,有点丑,别嫌丑啊,献丑下节不教你怎么点击了。
继续,有的文章有标签,有的文章无标签,那就做一个逻辑判断吧:
@unless ($article->tags->isEmpty()) <h5>Tags:</h5> <ul> @foreach ($article->tagsas $tag) <li> {{ $tag->name }} </li> @endforeach </ul>@endunless
打开 ArticlesController.php ,找到 edit() 方法,其实和 create() 的做法一样:
public function edit($id){ $tags=\App\Tag::lists('name','id'); $article = Article::findOrFail($id); return view('articles.edit',compact('article','tags'));}
访问一下 localhost:8888/articles/10/edit ,可以看到标签,但是不知道哪些已经是选过的,如何能标记一下呢?
打开 Article.php,我们新建一个方法:
public function getTagListAttribute(){ return $this->tags->lists('id')->all();}
相应的 form.blade.php 也得修改一下:
{!! Form::label('tag_list','Tags:') !!}{!! Form::select('tag_list[]',$tags,null,['class'=>'form-control','multiple']) !!}
细心的同学应该已经发现,为什么在 Article.php 中有一个 getTagListAttribute() 的方法,而且在 form.blade.php 中直接调用 tag_list 就能获取到被选中的 tag 的值。这是 laravel 功能,它能够通过命名方式来自动关联方法与对象。
现在访问 localhost:8888/articles/edit 你会发现可以显示之前选中的 tag 了。
最后修改 store() 方法中获取 tag 的方法:
public function store(ArticleRequest $request){ $article = Auth::user()->articles()->create($request->all()); $article->tags()->attach($request->input('tag_list')); return redirect('articles')->with([ 'flash_message'=>'Your article has been created!', 'flash_message_important'=>true]);}
好了,试着整个流程跑一遍,其实看似顺利,还是有瑕疵的。这个瑕疵留给你,或者下节课解决。