[{"data":1,"prerenderedAt":6700},["ShallowReactive",2],{"series-concrete5vue":3},[4,798,3355],{"id":5,"title":6,"body":7,"category":782,"createdAt":784,"description":785,"extension":786,"index":39,"meta":787,"navigation":54,"path":788,"publish":54,"seo":789,"series":790,"seriesTitle":785,"stem":791,"tag":792,"thumbnail":795,"updatedAt":796,"__hash__":797},"series\u002Fseries\u002Fconcrete5vue-1.md","Concrete5にVueCLIを使ってUIを構築する。1【環境構築編】",{"type":8,"value":9,"toc":769},"minimark",[10,14,17,22,25,108,111,116,119,122,135,138,143,146,149,152,155,158,166,169,172,178,181,187,193,216,219,223,226,229,232,247,391,397,408,415,600,615,627,633,701,708,711,714,719,747,752,759,762,765],[11,12,13],"p",{},"こんにちはjunです。今回はconcrete5というCMSでVueを使ったパッケージのUIを作成していこうと思います。今回の記事ではコンポーネントを作成する前の、concrete5にvueプロジェクトを作成してCMSに結びつける環境構築まで行います。",[11,15,16],{},"またConcrete5とそのカスタマイズ方法についてある程度熟知している人向け、基準としてはカスタムパッケージを作成したことがある人向けの記事となります。対象とするConcrete5のバージョンは8.4以降となります。",[18,19,21],"h2",{"id":20},"なぜvue","なぜVue？",[11,23,24],{},"なぜVueを使うのか。それはPHPとjqueryによるUI構築が非常に面倒になったからです。Concrete5にはフォーム（テキストエリアとかCMSからのファイル選択フォーム）をPHPで出力してくれる以下の様なヘルパーが存在します。",[26,27,32],"pre",{"className":28,"code":29,"language":30,"meta":31,"style":31},"language-php shiki shiki-themes material-theme-ocean","\u002F\u002F ヘルパーを読み込む\n$form = Core::make('helper\u002Fform');\n\n\u002F\u002Fテキストinput\necho $form->text($name, $default_value);\n\n\u002F\u002Fテキストエリア\necho $form-> textarea($name, $default_value);\n\n\u002F\u002F ファイルマネージャーヘルパー\n$file_selector = Core::make('helper\u002Fconcrete\u002Ffile_manager');\necho $file_selector->file('label', 'name_attr', 'Select Photo', $default_fileObj);\n","php","",[33,34,35,43,49,56,62,68,73,79,85,90,96,102],"code",{"__ignoreMap":31},[36,37,40],"span",{"class":38,"line":39},"line",1,[36,41,42],{},"\u002F\u002F ヘルパーを読み込む\n",[36,44,46],{"class":38,"line":45},2,[36,47,48],{},"$form = Core::make('helper\u002Fform');\n",[36,50,52],{"class":38,"line":51},3,[36,53,55],{"emptyLinePlaceholder":54},true,"\n",[36,57,59],{"class":38,"line":58},4,[36,60,61],{},"\u002F\u002Fテキストinput\n",[36,63,65],{"class":38,"line":64},5,[36,66,67],{},"echo $form->text($name, $default_value);\n",[36,69,71],{"class":38,"line":70},6,[36,72,55],{"emptyLinePlaceholder":54},[36,74,76],{"class":38,"line":75},7,[36,77,78],{},"\u002F\u002Fテキストエリア\n",[36,80,82],{"class":38,"line":81},8,[36,83,84],{},"echo $form-> textarea($name, $default_value);\n",[36,86,88],{"class":38,"line":87},9,[36,89,55],{"emptyLinePlaceholder":54},[36,91,93],{"class":38,"line":92},10,[36,94,95],{},"\u002F\u002F ファイルマネージャーヘルパー\n",[36,97,99],{"class":38,"line":98},11,[36,100,101],{},"$file_selector = Core::make('helper\u002Fconcrete\u002Ffile_manager');\n",[36,103,105],{"class":38,"line":104},12,[36,106,107],{},"echo $file_selector->file('label', 'name_attr', 'Select Photo', $default_fileObj);\n",[11,109,110],{},"上記のコードをページ上で実行すれば以下の様にフォームが現れます。",[112,113],"image-render",{":src":114,":width":115},"'_mix\u002Fformhelpertest-768x272.png'","'100%'",[11,117,118],{},"上から順番にテキストインプット、テキストエリア、そしてconcrete５純正のファイルマネージャーが出現します。name属性が与えられ、postを通じてデータを送ることができます。",[11,120,121],{},"簡単なブロックやパッケージUIであれば問題ないのですが、",[123,124,125,129,132],"ul",{},[126,127,128],"li",{},"フロント側のバリデーションを実装する",[126,130,131],{},"決まったフォームを複数生成する",[126,133,134],{},"フォーム同士が入力値で依存させる場合（入力値でフォームのパターンが変わる）",[11,136,137],{},"上記の際にPHPとjqueryだけでは非常に苦労して工数もかかります。",[139,140,142],"h3",{"id":141},"vueを使えばリッチなuiが作成可能","Vueを使えばリッチなUIが作成可能",[11,144,145],{},"今流行りのリッチなUI、フォームはほとんどがVue、React、Backbone,jsなどHTMLテンプレート、jsによる状態管理を行うことで簡単に実装できます。工数を抑えつつも、これらのライブラリを用いることでリッチなUIを作成することもできます。",[11,147,148],{},"今回の記事ではVue CLIを用いて作成したUIをconcrete5のパッケージ上で表示させ、入力内容の追加・更新・削除まで行える様に実装していきます。原理がわかれば意外と簡単です。",[18,150,151],{"id":151},"パッケージの制作準備",[139,153,154],{"id":154},"パッケージの専用のディレクトリを作成",[11,156,157],{},"それではVueで構築したUIを持つパッケージを作成していきましょう。pckageディレクトリ配下にvuetestというカスタムパッケージディレクトリを作ります。またディレクトリ構成は以下の通りにします。",[26,159,164],{"className":160,"code":162,"language":163},[161],"language-text","documentroot $ cd .\u002Fpackage\npackage $ mkdir vuetest && touch ...\npackage $ tree vuetest\n.\u002F\n└── vuetest\n    ├── controller.php\n    ├── controllers\n    │   └── single_page\n    │       └── dashboard\n    │           └── vuetest.php\n    ├── db.xml\n    ├── icon.png\n    ├── js\n    │\n    └── single_pages\n        └── dashboard\n            └── vuetest\n                └── view.php\n","text",[33,165,162],{"__ignoreMap":31},[139,167,168],{"id":168},"vueプロジェクトを作成",[11,170,171],{},"パッケージに必要なコントローラーやUIを表示するダッシュボード上のシングルページとそのコントローラーも用意します。そしてjsディレクトリを作成してその中にvue cliを用いてプロジェクトを作成します。",[26,173,176],{"className":174,"code":175,"language":163},[161],"package $ cd vuetest\u002Fjs\njs $ vue create packageui\n\nVue CLI v4.4.6\n? Please pick a preset: default (babel, eslint) #default\n\nVue CLI v4.4.6\n✨  Creating project in documentroot\u002Fvuetest\u002Fjs\u002Fpackageui.\n🗃  Initializing git repository...\n⚙️  Installing CLI plugins. This might take a while... \n\n🎉  Successfully created project packageui.\n\njs $ cd packageui && tree -L 1\n.\n├── README.md\n├── babel.config.js\n├── node_modules\n├── package-lock.json\n├── package.json\n├── public\n",[33,177,175],{"__ignoreMap":31},[11,179,180],{},"無事にvueのプロジェクトが作成されました。concrete5との都合によりvue.config.jsファイルを作成してwebpackの設定をいじります。",[26,182,185],{"className":183,"code":184,"language":163},[161],"packageui $ touch vue.config.js\n",[33,186,184],{"__ignoreMap":31},[26,188,191],{"className":189,"code":190,"language":163},[161],"module.exports = {\n    configureWebpack: {\n      output: {\n        filename: '[name].js',\n        chunkFilename: '[name].js'\n      }\n    },\n  }\n",[33,192,190],{"__ignoreMap":31},[11,194,195,196,199,200,203,204,207,208,211,212,215],{},"これは ",[33,197,198],{},"npm run build",",",[33,201,202],{},"npm run build --mode development","で",[33,205,206],{},".vue","ファイルを",[33,209,210],{},".js","ファイルにコンパイルして",[33,213,214],{},"\u002Fdist","配下に配置される時に名前がいつも同じになる様に設定します。",[11,217,218],{},"buildをするとビルドされたファイルの名前にはハッシュされた英数字がつくのですが、これがビルドの度にころころ変わります。Concrete5でjsファイルをロードする場合は設定した名前が一致しないと読み込めませんので、ビルドの際に設定を変えなくて済む様に上記の設定をします。",[220,221,222],"h4",{"id":222},"もし複数のパッケージで共通のvueファイルを用いる場合",[11,224,225],{},"今回は vuetestというパッケージとそのディレクトリ配下に専用のvueプロジェクトを作成しますす。しかし複数のパッケージでvueファイルを使用したい場合、applicationディレクトリにjsディレクトリを作成し、vueプロジェクトを作成してください。",[139,227,228],{"id":228},"コンパイルしたjsファイルをconcrete5と結びつける",[11,230,231],{},"vue cliでビルドするとdist配下にコンパイルされたjsファイルが生成されます。そのファイルとレンダー先のconcrete5上のページ（シングルページ）で読み込める様に、このjsファイルをCMSが読み込める様に設定します。",[11,233,234,235,238,239,242,243,246],{},"まずとりあえず以下の",[33,236,237],{},"main.js","をビルドしてみます。レンダリング先に ",[33,240,241],{},"id=\"app\""," という要素があれば",[33,244,245],{},"Appコンポーネント","がレンダーされます。",[26,248,253],{"className":249,"code":250,"filename":251,"language":252,"meta":31,"style":31},"language-javascript shiki shiki-themes material-theme-ocean","import Vue from 'vue'\nimport App from '.\u002FApp.vue'\n\nVue.config.productionTip = false\n\nnew Vue({\n  render: h => h(App),\n}).$mount('#app')\n","src\u002Fmain.js","javascript",[33,254,255,279,295,299,322,326,341,365],{"__ignoreMap":31},[36,256,257,261,265,268,272,276],{"class":38,"line":39},[36,258,260],{"class":259},"s6cf3","import",[36,262,264],{"class":263},"s0W1g"," Vue ",[36,266,267],{"class":259},"from",[36,269,271],{"class":270},"sAklC"," '",[36,273,275],{"class":274},"sfyAc","vue",[36,277,278],{"class":270},"'\n",[36,280,281,283,286,288,290,293],{"class":38,"line":45},[36,282,260],{"class":259},[36,284,285],{"class":263}," App ",[36,287,267],{"class":259},[36,289,271],{"class":270},[36,291,292],{"class":274},".\u002FApp.vue",[36,294,278],{"class":270},[36,296,297],{"class":38,"line":51},[36,298,55],{"emptyLinePlaceholder":54},[36,300,301,304,307,310,312,315,318],{"class":38,"line":58},[36,302,303],{"class":263},"Vue",[36,305,306],{"class":270},".",[36,308,309],{"class":263},"config",[36,311,306],{"class":270},[36,313,314],{"class":263},"productionTip ",[36,316,317],{"class":270},"=",[36,319,321],{"class":320},"sbqyR"," false\n",[36,323,324],{"class":38,"line":64},[36,325,55],{"emptyLinePlaceholder":54},[36,327,328,331,335,338],{"class":38,"line":70},[36,329,330],{"class":270},"new",[36,332,334],{"class":333},"sdLwU"," Vue",[36,336,337],{"class":263},"(",[36,339,340],{"class":270},"{\n",[36,342,343,346,349,353,357,359,362],{"class":38,"line":75},[36,344,345],{"class":333},"  render",[36,347,348],{"class":270},":",[36,350,352],{"class":351},"s7ZW3"," h",[36,354,356],{"class":355},"sJ14y"," =>",[36,358,352],{"class":333},[36,360,361],{"class":263},"(App)",[36,363,364],{"class":270},",\n",[36,366,367,370,373,375,378,380,383,386,388],{"class":38,"line":81},[36,368,369],{"class":270},"}",[36,371,372],{"class":263},")",[36,374,306],{"class":270},[36,376,377],{"class":333},"$mount",[36,379,337],{"class":263},[36,381,382],{"class":270},"'",[36,384,385],{"class":274},"#app",[36,387,382],{"class":270},[36,389,390],{"class":263},")\n",[26,392,395],{"className":393,"code":394,"language":163},[161],"packageui ＄ npm run build\n.\n├── README.md\n├── babel.config.js\n├── dist\n│   ├── app.js\n│   ├── app.js.map\n│   ├── chunk-vendors.js\n│   ├── chunk-vendors.js.map\n│   ├── css\n│   ├── favicon.ico\n│   ├── img\n│   └── index.html\n├\n",[33,396,394],{"__ignoreMap":31},[11,398,399,400,403,404,407],{},"ビルド成功。いらないものもありますが、",[33,401,402],{},"app.js","と",[33,405,406],{},"chunk-vendors.js","が読み込まれる様にすればOKです。",[11,409,410,411,414],{},"パッケージ専用のjsファイルで作成する場合はパッケージのインストールコントローラ（",[33,412,413],{},"package\u002Fvuetest\u002Fcontroller.php","）に以下の様な記述をします。",[26,416,419],{"className":28,"code":417,"filename":418,"language":30,"meta":31,"style":31},"\u003C?php\nnamespace Concrete\\Package\\Vuetest;\ndefined('C5_EXECUTE') or die('Access Denied.');\nuse \\Concrete\\Core\\Asset\\AssetList;\nuse \\Concrete\\Core\\Asset\\Asset;\n\nclass Controller extends \\Concrete\\Core\\Package\\Package {\n    protected $pkgHandle = 'vuetest';\n    protected $appVersionRequired = '5.7.4';\n    protected $pkgVersion = '1.0.0';\n\n    public function on_start()\n    {\n        $al = AssetList::getInstance();\n        $al->register(\n            'javascript', 'package-vue-build', 'js\u002Fpackageui\u002Fdist\u002Fapp.js',\n            array('version' => '1.0.0', 'position' => Asset::ASSET_POSITION_FOOTER, 'combine' => true),\n            $this->pkgHandle\n        );\n        \n        $al->register(\n            'javascript', 'package-vue-chunk', 'js\u002Fpackageui\u002Fdist\u002Fchunk-vendors.js',\n            array('version' => '1.0.0', 'position' => Asset::ASSET_POSITION_FOOTER, 'combine' => true),\n            $this->pkgHandle\n        );\n        \n        $al->registerGroup('package-vue-production', array(\n            array('javascript', 'package-vue-build'),\n            array('javascript', 'package-vue-chunk'),\n        )); \n    }\n...\n}\n","controller.php",[33,420,421,426,431,436,441,446,450,455,460,465,470,474,479,485,491,497,503,509,515,521,527,532,538,543,548,553,558,564,570,576,582,588,594],{"__ignoreMap":31},[36,422,423],{"class":38,"line":39},[36,424,425],{},"\u003C?php\n",[36,427,428],{"class":38,"line":45},[36,429,430],{},"namespace Concrete\\Package\\Vuetest;\n",[36,432,433],{"class":38,"line":51},[36,434,435],{},"defined('C5_EXECUTE') or die('Access Denied.');\n",[36,437,438],{"class":38,"line":58},[36,439,440],{},"use \\Concrete\\Core\\Asset\\AssetList;\n",[36,442,443],{"class":38,"line":64},[36,444,445],{},"use \\Concrete\\Core\\Asset\\Asset;\n",[36,447,448],{"class":38,"line":70},[36,449,55],{"emptyLinePlaceholder":54},[36,451,452],{"class":38,"line":75},[36,453,454],{},"class Controller extends \\Concrete\\Core\\Package\\Package {\n",[36,456,457],{"class":38,"line":81},[36,458,459],{},"    protected $pkgHandle = 'vuetest';\n",[36,461,462],{"class":38,"line":87},[36,463,464],{},"    protected $appVersionRequired = '5.7.4';\n",[36,466,467],{"class":38,"line":92},[36,468,469],{},"    protected $pkgVersion = '1.0.0';\n",[36,471,472],{"class":38,"line":98},[36,473,55],{"emptyLinePlaceholder":54},[36,475,476],{"class":38,"line":104},[36,477,478],{},"    public function on_start()\n",[36,480,482],{"class":38,"line":481},13,[36,483,484],{},"    {\n",[36,486,488],{"class":38,"line":487},14,[36,489,490],{},"        $al = AssetList::getInstance();\n",[36,492,494],{"class":38,"line":493},15,[36,495,496],{},"        $al->register(\n",[36,498,500],{"class":38,"line":499},16,[36,501,502],{},"            'javascript', 'package-vue-build', 'js\u002Fpackageui\u002Fdist\u002Fapp.js',\n",[36,504,506],{"class":38,"line":505},17,[36,507,508],{},"            array('version' => '1.0.0', 'position' => Asset::ASSET_POSITION_FOOTER, 'combine' => true),\n",[36,510,512],{"class":38,"line":511},18,[36,513,514],{},"            $this->pkgHandle\n",[36,516,518],{"class":38,"line":517},19,[36,519,520],{},"        );\n",[36,522,524],{"class":38,"line":523},20,[36,525,526],{},"        \n",[36,528,530],{"class":38,"line":529},21,[36,531,496],{},[36,533,535],{"class":38,"line":534},22,[36,536,537],{},"            'javascript', 'package-vue-chunk', 'js\u002Fpackageui\u002Fdist\u002Fchunk-vendors.js',\n",[36,539,541],{"class":38,"line":540},23,[36,542,508],{},[36,544,546],{"class":38,"line":545},24,[36,547,514],{},[36,549,551],{"class":38,"line":550},25,[36,552,520],{},[36,554,556],{"class":38,"line":555},26,[36,557,526],{},[36,559,561],{"class":38,"line":560},27,[36,562,563],{},"        $al->registerGroup('package-vue-production', array(\n",[36,565,567],{"class":38,"line":566},28,[36,568,569],{},"            array('javascript', 'package-vue-build'),\n",[36,571,573],{"class":38,"line":572},29,[36,574,575],{},"            array('javascript', 'package-vue-chunk'),\n",[36,577,579],{"class":38,"line":578},30,[36,580,581],{},"        )); \n",[36,583,585],{"class":38,"line":584},31,[36,586,587],{},"    }\n",[36,589,591],{"class":38,"line":590},32,[36,592,593],{},"...\n",[36,595,597],{"class":38,"line":596},33,[36,598,599],{},"}\n",[11,601,602,603,606,607,610,611,614],{},"vuetestパッケージのコントローラーで",[33,604,605],{},"$al->register","を用いて、パスで指定したjsファイルを登録します。２つあるのでを",[33,608,609],{},"$al->registerGroup","用いてのp",[33,612,613],{},"ackage-vue-production","名前で２つのjsファイルを読み込む様にグルーピングします。",[11,616,617,618,622,623,626],{},"concrete5ではこの様なjs\u002Fcssのアセット登録システムがあり、登録をすれば適当にアセットが読み込むことができる様になります。",[619,620,621],"strong",{},"パッケージのコントローラーでは登録をした"," ので、次はjsファイルが必要な",[619,624,625],{},"ページのコントローラーで呼び出し"," を行います。",[11,628,629,632],{},[33,630,631],{},"vuetest\u002Fsingle_pages\u002Fdashboard\u002Fvuetest\u002Fview.php"," に以下の様に記述します。",[26,634,636],{"className":28,"code":635,"language":30,"meta":31,"style":31},"\u003C?php\nnamespace Concrete\\Package\\Vuetest\\Controller\\SinglePage\\Dashboard;\ndefined('C5_EXECUTE') or die('Access Denied.');\nuse \\Concrete\\Core\\Page\\Controller\\DashboardPageController;\n\nclass Vuetest extends DashboardPageController\n{\n    public $packageHandle = 'vuetest';\n\n    public function view() {\n        $this->requireAsset('package-vue-production');\n        $this->set('success', 'My success message');\n    }\n}\n",[33,637,638,642,647,651,656,660,665,669,674,678,683,688,693,697],{"__ignoreMap":31},[36,639,640],{"class":38,"line":39},[36,641,425],{},[36,643,644],{"class":38,"line":45},[36,645,646],{},"namespace Concrete\\Package\\Vuetest\\Controller\\SinglePage\\Dashboard;\n",[36,648,649],{"class":38,"line":51},[36,650,435],{},[36,652,653],{"class":38,"line":58},[36,654,655],{},"use \\Concrete\\Core\\Page\\Controller\\DashboardPageController;\n",[36,657,658],{"class":38,"line":64},[36,659,55],{"emptyLinePlaceholder":54},[36,661,662],{"class":38,"line":70},[36,663,664],{},"class Vuetest extends DashboardPageController\n",[36,666,667],{"class":38,"line":75},[36,668,340],{},[36,670,671],{"class":38,"line":81},[36,672,673],{},"    public $packageHandle = 'vuetest';\n",[36,675,676],{"class":38,"line":87},[36,677,55],{"emptyLinePlaceholder":54},[36,679,680],{"class":38,"line":92},[36,681,682],{},"    public function view() {\n",[36,684,685],{"class":38,"line":98},[36,686,687],{},"        $this->requireAsset('package-vue-production');\n",[36,689,690],{"class":38,"line":104},[36,691,692],{},"        $this->set('success', 'My success message');\n",[36,694,695],{"class":38,"line":481},[36,696,587],{},[36,698,699],{"class":38,"line":487},[36,700,599],{},[11,702,703,704,707],{},"この",[33,705,706],{},"$this->requireAsset('package-vue-production');","で「先ほど登録したjsアセットをこのページで読み込め！」と命令しています。設定した後、実際に該当ページで探してみましょう。",[112,709],{":src":710,":width":115},"'_mix\u002Fsc-2020-08-01-19.52.09-768x133.png'",[11,712,713],{},"いました。\u002Fpackages\u002Fvuetest\u002Fjs\u002Fdist\u002F** と指定したパスにて読み込まれています。それではid=\"app\"を持つ適当なdivを作成して再度みてみましょう。",[11,715,716,718],{},[33,717,631],{}," にて",[26,720,723],{"className":28,"code":721,"filename":722,"language":30,"meta":31,"style":31},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\n\u003Cdiv id=\"app\">\u003C\u002Fdiv>\n","view.php",[33,724,725,729,733,738,742],{"__ignoreMap":31},[36,726,727],{"class":38,"line":39},[36,728,425],{},[36,730,731],{"class":38,"line":45},[36,732,435],{},[36,734,735],{"class":38,"line":51},[36,736,737],{},"?>\n",[36,739,740],{"class":38,"line":58},[36,741,55],{"emptyLinePlaceholder":54},[36,743,744],{"class":38,"line":64},[36,745,746],{},"\u003Cdiv id=\"app\">\u003C\u002Fdiv>\n",[112,748],{":src":749,":width":750,":center":751},"'_mix\u002Fsh-2020-08-01-19.56.01-768x812.png'","'500px'","true",[11,753,754,755,758],{},"パスの関係上レイアウトが崩れ、画像が読み込めていませんがvue側で記述した内容が無事にレンダリングされています。これでvueとconcrete5のセッティングは完了です。vueプロジェクトでコンポーネントを作成しながら、適切な",[33,756,757],{},"id","を用いてページ上にレンダーします。",[18,760,761],{"id":761},"次はフォームコンポーネントの作成",[11,763,764],{},"以上がconcrete5のパッケージ上にvueプロジェクトを作成して、concrete5に結びつける方法でした。これでvueを使え、レンダーされる環境は整ったので次は情報を登録するための登録フォームと編集画面の作成を行っていきます。",[766,767,768],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}",{"title":31,"searchDepth":51,"depth":51,"links":770},[771,774,781],{"id":20,"depth":45,"text":21,"children":772},[773],{"id":141,"depth":51,"text":142},{"id":151,"depth":45,"text":151,"children":775},[776,777,780],{"id":154,"depth":51,"text":154},{"id":168,"depth":51,"text":168,"children":778},[779],{"id":222,"depth":58,"text":222},{"id":228,"depth":51,"text":228},{"id":761,"depth":45,"text":761},[783],"devstack","2020-08-25","Concrete5にVueCLIを使ってUIを構築する。","md",{},"\u002Fseries\u002Fconcrete5vue-1",{"title":6,"description":785},"concrete5vue","series\u002Fconcrete5vue-1",[793,794,275],"concrete5","js","_mix\u002Fvuewithconcrete.png",null,"SFdt3_VrU2GVgYjfNjC32zyOKCtr79IKO3992JqFQJo",{"id":799,"title":800,"body":801,"category":3347,"createdAt":3348,"description":3349,"extension":786,"index":45,"meta":3350,"navigation":54,"path":809,"publish":54,"seo":3351,"series":790,"seriesTitle":785,"stem":3352,"tag":3353,"thumbnail":795,"updatedAt":796,"__hash__":3354},"series\u002Fseries\u002Fconcrete5vue-2.md","Concrete5にVueCLIを使ってUIを構築する。2【コンポーネント作成・データ登録編】",{"type":8,"value":802,"toc":3326},[803,811,814,817,820,823,837,841,844,847,851,854,1077,1080,1084,1088,1091,1097,1104,1182,1185,1208,1215,1218,1240,1246,1249,1252,1258,1261,1264,1555,1558,1680,1688,1795,1802,1805,1817,1820,1823,1826,1830,1844,2268,2271,2274,2914,2929,2950,2953,2956,2961,2965,2971,2977,2987,2993,2999,3002,3005,3208,3221,3239,3243,3246,3265,3275,3278,3281,3284,3290,3293,3296,3299,3302,3306,3309,3320,3323],[11,804,805,806,810],{},"こんにちはjunです。",[807,808,6],"a",{"href":809},"\u002Fseries\u002Fconcrete5vue-2","の記事の続きを書いていきます。",[11,812,813],{},"今回の記事では",[11,815,816],{},"どんなフォームを作成するのか。\nテキストインプットを用いたフォームの簡易実装\nデータの保存のバックエンド実装\nを行いたいと思います。ファイルマネージャー、リッチテキストエディタをvueでレンダリングする方法は追加・編集・一覧化が終わった後に書きたいと思います。まずは簡単なフォーム（テキスト）とデータの保存をvueとともに実装していきましょう。",[18,818,819],{"id":819},"最終的に作成するフォーム",[11,821,822],{},"「アルバム管理」たるものを作成しようと思います。インスタグラム的な物で、機能は以下の通りです。",[123,824,825,828,831,834],{},[126,826,827],{},"1つのアルバムに複数枚の画像を自由に登録できる。数は基本的に無制限、最低１枚",[126,829,830],{},"画像と一緒にその画像に関する情報をリッチテキストエディタで編集できる。",[126,832,833],{},"画像は順番の並び替え、追加、削除が可能。",[126,835,836],{},"ページ内ではブロックを通じてアルバムの写真を出力できる。",[139,838,840],{"id":839},"ワイヤーフレーム超簡素","ワイヤーフレーム（超簡素）",[112,842],{":src":843,":width":115},"'_mix\u002Fvueconcrete2-1.jpeg'",[112,845],{":src":846,":width":115},"'_mix\u002Fslide-2.jpeg'",[18,848,850],{"id":849},"db構造","DB構造",[11,852,853],{},"db.xmlを用いて以下のようなテーブルを作成しておきます。",[26,855,860],{"className":856,"code":857,"filename":858,"language":859,"meta":31,"style":31},"language-xml shiki shiki-themes material-theme-ocean","\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003Cschema\n  xmlns=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5\"\n  xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\n  xsi:schemaLocation=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5 http:\u002F\u002Fconcrete5.github.io\u002Fdoctrine-xml\u002Fdoctrine-xml-0.5.xsd\">\n\n\u003Ctable name=\"album\">\n    \u003Cfield name=\"id\" type=\"integer\">\n        \u003Cautoincrement\u002F>\n        \u003Ckey\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"title\" type=\"string\" size=\"255\"\u002F>\n    \u003Cfield name=\"created\" type=\"datetime\">\n      \u003Cdefault value=\"1000-01-01 00:00:00\"\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"modified\" type=\"timestamp\">\n      \u003Cdeftimestamp\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n\u003C\u002Ftable>\n\n\u003Ctable name=\"albumPics\">\n    \u003Cfield name=\"id\" type=\"integer\">\n        \u003Cautoincrement\u002F>\n        \u003Ckey\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"albumID\" type=\"integer\">\n        \u003Cunsigned\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"fID\" type=\"integer\">\n        \u003Cunsigned\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"html\" type=\"text\" size=\"65535\"\u002F>\n    \u003Cfield name=\"created\" type=\"datetime\">\n      \u003Cdefault value=\"1000-01-01 00:00:00\"\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"modified\" type=\"timestamp\">\n      \u003Cdeftimestamp\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n\u003C\u002Ftable>\n\n\u003C\u002Fschema>\n","db.xml","xml",[33,861,862,867,872,877,882,887,891,896,901,906,911,916,921,926,931,936,940,945,950,954,958,963,967,972,976,980,984,988,993,998,1002,1007,1011,1015,1021,1026,1031,1036,1041,1046,1051,1056,1061,1066,1071],{"__ignoreMap":31},[36,863,864],{"class":38,"line":39},[36,865,866],{},"\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",[36,868,869],{"class":38,"line":45},[36,870,871],{},"\u003Cschema\n",[36,873,874],{"class":38,"line":51},[36,875,876],{},"  xmlns=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5\"\n",[36,878,879],{"class":38,"line":58},[36,880,881],{},"  xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\n",[36,883,884],{"class":38,"line":64},[36,885,886],{},"  xsi:schemaLocation=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5 http:\u002F\u002Fconcrete5.github.io\u002Fdoctrine-xml\u002Fdoctrine-xml-0.5.xsd\">\n",[36,888,889],{"class":38,"line":70},[36,890,55],{"emptyLinePlaceholder":54},[36,892,893],{"class":38,"line":75},[36,894,895],{},"\u003Ctable name=\"album\">\n",[36,897,898],{"class":38,"line":81},[36,899,900],{},"    \u003Cfield name=\"id\" type=\"integer\">\n",[36,902,903],{"class":38,"line":87},[36,904,905],{},"        \u003Cautoincrement\u002F>\n",[36,907,908],{"class":38,"line":92},[36,909,910],{},"        \u003Ckey\u002F>\n",[36,912,913],{"class":38,"line":98},[36,914,915],{},"    \u003C\u002Ffield>\n",[36,917,918],{"class":38,"line":104},[36,919,920],{},"    \u003Cfield name=\"title\" type=\"string\" size=\"255\"\u002F>\n",[36,922,923],{"class":38,"line":481},[36,924,925],{},"    \u003Cfield name=\"created\" type=\"datetime\">\n",[36,927,928],{"class":38,"line":487},[36,929,930],{},"      \u003Cdefault value=\"1000-01-01 00:00:00\"\u002F>\n",[36,932,933],{"class":38,"line":493},[36,934,935],{},"      \u003Cnotnull\u002F>\n",[36,937,938],{"class":38,"line":499},[36,939,915],{},[36,941,942],{"class":38,"line":505},[36,943,944],{},"    \u003Cfield name=\"modified\" type=\"timestamp\">\n",[36,946,947],{"class":38,"line":511},[36,948,949],{},"      \u003Cdeftimestamp\u002F>\n",[36,951,952],{"class":38,"line":517},[36,953,935],{},[36,955,956],{"class":38,"line":523},[36,957,915],{},[36,959,960],{"class":38,"line":529},[36,961,962],{},"\u003C\u002Ftable>\n",[36,964,965],{"class":38,"line":534},[36,966,55],{"emptyLinePlaceholder":54},[36,968,969],{"class":38,"line":540},[36,970,971],{},"\u003Ctable name=\"albumPics\">\n",[36,973,974],{"class":38,"line":545},[36,975,900],{},[36,977,978],{"class":38,"line":550},[36,979,905],{},[36,981,982],{"class":38,"line":555},[36,983,910],{},[36,985,986],{"class":38,"line":560},[36,987,915],{},[36,989,990],{"class":38,"line":566},[36,991,992],{},"    \u003Cfield name=\"albumID\" type=\"integer\">\n",[36,994,995],{"class":38,"line":572},[36,996,997],{},"        \u003Cunsigned\u002F>\n",[36,999,1000],{"class":38,"line":578},[36,1001,915],{},[36,1003,1004],{"class":38,"line":584},[36,1005,1006],{},"    \u003Cfield name=\"fID\" type=\"integer\">\n",[36,1008,1009],{"class":38,"line":590},[36,1010,997],{},[36,1012,1013],{"class":38,"line":596},[36,1014,915],{},[36,1016,1018],{"class":38,"line":1017},34,[36,1019,1020],{},"    \u003Cfield name=\"html\" type=\"text\" size=\"65535\"\u002F>\n",[36,1022,1024],{"class":38,"line":1023},35,[36,1025,925],{},[36,1027,1029],{"class":38,"line":1028},36,[36,1030,930],{},[36,1032,1034],{"class":38,"line":1033},37,[36,1035,935],{},[36,1037,1039],{"class":38,"line":1038},38,[36,1040,915],{},[36,1042,1044],{"class":38,"line":1043},39,[36,1045,944],{},[36,1047,1049],{"class":38,"line":1048},40,[36,1050,949],{},[36,1052,1054],{"class":38,"line":1053},41,[36,1055,935],{},[36,1057,1059],{"class":38,"line":1058},42,[36,1060,915],{},[36,1062,1064],{"class":38,"line":1063},43,[36,1065,962],{},[36,1067,1069],{"class":38,"line":1068},44,[36,1070,55],{"emptyLinePlaceholder":54},[36,1072,1074],{"class":38,"line":1073},45,[36,1075,1076],{},"\u003C\u002Fschema>\n",[11,1078,1079],{},"1アルバムに対して不定数の画像が登録されるので上記の様なDBになっています。",[18,1081,1083],{"id":1082},"パッケージのビューphpとvueのsrc構成","パッケージのビューPHPとvueのSrc構成",[139,1085,1087],{"id":1086},"パッケージ側phpの下準備","パッケージ側（PHP）の下準備",[11,1089,1090],{},"それではアルバムののフォームを作っていきましょう。前回インストールした「vuetest」にてフォーム用のシングルページを作成します。",[26,1092,1095],{"className":1093,"code":1094,"language":163},[161],"vuetest\n├── controller.php \u002F\u002Fこれはパッケージのcontroller\n├── controllers\n│   └── single_page\n│       └── dashboard\n│           └── vuetest.php\n└── single_pages\n    └── dashboard\n        └── vuetest\n            ├── add.php   \u002F\u002F追加画面シングルページ\n            ├── edit.php  \u002F\u002F編集画面シングルページ\n            └── view.php\n",[33,1096,1094],{"__ignoreMap":31},[11,1098,1099,1100,1103],{},"そしてシングルページのコントローラーである",[33,1101,1102],{},"vuetest.php","で以下の様に入力",[26,1105,1107],{"className":28,"code":1106,"filename":1102,"language":30,"meta":31,"style":31},"class Vuetest extends DashboardPageController\n{\n    public $packageHandle = 'vuetest';\n\n   \u002F\u002Fvuetest のシングルページでvueのjsファイルを読み込む様にする。\n　　public function on_start() {\n        $this->requireAsset('package-vue-production');\n    }\n\n    public function view() {\n    }\n\n    \u002F\u002F \u002Fdashboard\u002Fvuetest\u002F に \u002Fadd というURLを追加できる\n    public function add(){\n        $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n    }\n}\n",[33,1108,1109,1113,1117,1121,1125,1130,1135,1139,1143,1147,1151,1155,1159,1164,1169,1174,1178],{"__ignoreMap":31},[36,1110,1111],{"class":38,"line":39},[36,1112,664],{},[36,1114,1115],{"class":38,"line":45},[36,1116,340],{},[36,1118,1119],{"class":38,"line":51},[36,1120,673],{},[36,1122,1123],{"class":38,"line":58},[36,1124,55],{"emptyLinePlaceholder":54},[36,1126,1127],{"class":38,"line":64},[36,1128,1129],{},"   \u002F\u002Fvuetest のシングルページでvueのjsファイルを読み込む様にする。\n",[36,1131,1132],{"class":38,"line":70},[36,1133,1134],{},"　　public function on_start() {\n",[36,1136,1137],{"class":38,"line":75},[36,1138,687],{},[36,1140,1141],{"class":38,"line":81},[36,1142,587],{},[36,1144,1145],{"class":38,"line":87},[36,1146,55],{"emptyLinePlaceholder":54},[36,1148,1149],{"class":38,"line":92},[36,1150,682],{},[36,1152,1153],{"class":38,"line":98},[36,1154,587],{},[36,1156,1157],{"class":38,"line":104},[36,1158,55],{"emptyLinePlaceholder":54},[36,1160,1161],{"class":38,"line":481},[36,1162,1163],{},"    \u002F\u002F \u002Fdashboard\u002Fvuetest\u002F に \u002Fadd というURLを追加できる\n",[36,1165,1166],{"class":38,"line":487},[36,1167,1168],{},"    public function add(){\n",[36,1170,1171],{"class":38,"line":493},[36,1172,1173],{},"        $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n",[36,1175,1176],{"class":38,"line":499},[36,1177,587],{},[36,1179,1180],{"class":38,"line":505},[36,1181,599],{},[11,1183,1184],{},"すると\u002Fdashboard\u002Fvuetest\u002Fadd というURLを叩くとadd.phpが表示されます。",[26,1186,1189],{"className":28,"code":1187,"filename":1188,"language":30,"meta":31,"style":31},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\u003Cp>add用のページだよ\u003C\u002Fp>\n","add.php",[33,1190,1191,1195,1199,1203],{"__ignoreMap":31},[36,1192,1193],{"class":38,"line":39},[36,1194,425],{},[36,1196,1197],{"class":38,"line":45},[36,1198,435],{},[36,1200,1201],{"class":38,"line":51},[36,1202,737],{},[36,1204,1205],{"class":38,"line":58},[36,1206,1207],{},"\u003Cp>add用のページだよ\u003C\u002Fp>\n",[11,1209,1210,1211],{},"↓\n",[112,1212],{":src":1213,":width":1214,":center":751},"'_mix\u002Fscsh-2020-08-26-21.34.56-768x436.png'","'600px'",[11,1216,1217],{},"ページの表示が確認できたら、add.phpに以下の様に変更しておきます。",[26,1219,1221],{"className":28,"code":1220,"filename":1188,"language":30,"meta":31,"style":31},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\u003Cdiv id=\"add\">\u003C\u002Fdiv>\n",[33,1222,1223,1227,1231,1235],{"__ignoreMap":31},[36,1224,1225],{"class":38,"line":39},[36,1226,425],{},[36,1228,1229],{"class":38,"line":45},[36,1230,435],{},[36,1232,1233],{"class":38,"line":51},[36,1234,737],{},[36,1236,1237],{"class":38,"line":58},[36,1238,1239],{},"\u003Cdiv id=\"add\">\u003C\u002Fdiv>\n",[11,1241,703,1242,1245],{},[33,1243,1244],{},"\u003Cdiv id=”app>\u003C\u002Fdiv>","としたところがvueコンポーネントを流し込むエントリーになります。フォームのビューファイルであるadd.phpはこれだけでおしまいです。",[18,1247,1248],{"id":1248},"vue側の準備",[11,1250,1251],{},"ではvue側も作っていきましょう。src配下は以下の様に構成します。",[26,1253,1256],{"className":1254,"code":1255,"language":163},[161],"├── src\n   ├── add.vue\n   ├── components\n   │   └── form.vue\n   ├── edit.vue\n   ├── index.vue\n   └── main.js\n",[33,1257,1255],{"__ignoreMap":31},[11,1259,1260],{},"index.vue、add.vue、edit.vueそれぞれが一覧・追加・編集ページのUIを構築します。しかしedit.vueとadd.vueは入力項目が同じで、初期値があるかないかの違いだけです。そのため共通のコンポーネントform.vueを作成します。",[11,1262,1263],{},"form.vueはひとまず以下の様に設定しておきます。",[26,1265,1269],{"className":1266,"code":1267,"filename":1268,"language":275,"meta":31,"style":31},"language-vue shiki shiki-themes material-theme-ocean","\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Cp>vueレンダリングテスト\u003C\u002Fp>\n        \n        \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n            \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                \u003Cbutton class=\"pull-left btn btn-primary\">\n                    一覧へ戻る\n                \u003C\u002Fbutton>\n                \u003Ca href=\"#\" class=\"pull-right btn btn-primary\">\n                    登録\n                \u003C\u002Fa>\n            \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n    name:'albumForm',\n    props:['isEdit']\n}\n\u003C\u002Fscript>\n","form.vue",[33,1270,1271,1283,1306,1326,1330,1349,1369,1390,1395,1404,1435,1440,1448,1457,1466,1475,1483,1487,1496,1507,1523,1543,1547],{"__ignoreMap":31},[36,1272,1273,1276,1280],{"class":38,"line":39},[36,1274,1275],{"class":270},"\u003C",[36,1277,1279],{"class":1278},"s-wAU","template",[36,1281,1282],{"class":270},">\n",[36,1284,1285,1288,1291,1294,1296,1299,1302,1304],{"class":38,"line":45},[36,1286,1287],{"class":270},"    \u003C",[36,1289,1290],{"class":1278},"div",[36,1292,1293],{"class":355}," class",[36,1295,317],{"class":270},[36,1297,1298],{"class":270},"\"",[36,1300,1301],{"class":274},"ccm-dashboard-content-inner",[36,1303,1298],{"class":270},[36,1305,1282],{"class":270},[36,1307,1308,1311,1313,1316,1319,1322,1324],{"class":38,"line":51},[36,1309,1310],{"class":270},"        \u003C",[36,1312,11],{"class":1278},[36,1314,1315],{"class":270},">",[36,1317,1318],{"class":263},"vueレンダリングテスト",[36,1320,1321],{"class":270},"\u003C\u002F",[36,1323,11],{"class":1278},[36,1325,1282],{"class":270},[36,1327,1328],{"class":38,"line":58},[36,1329,526],{"class":263},[36,1331,1332,1334,1336,1338,1340,1342,1345,1347],{"class":38,"line":64},[36,1333,1310],{"class":270},[36,1335,1290],{"class":1278},[36,1337,1293],{"class":355},[36,1339,317],{"class":270},[36,1341,1298],{"class":270},[36,1343,1344],{"class":274},"ccm-dashboard-form-actions-wrapper",[36,1346,1298],{"class":270},[36,1348,1282],{"class":270},[36,1350,1351,1354,1356,1358,1360,1362,1365,1367],{"class":38,"line":70},[36,1352,1353],{"class":270},"            \u003C",[36,1355,1290],{"class":1278},[36,1357,1293],{"class":355},[36,1359,317],{"class":270},[36,1361,1298],{"class":270},[36,1363,1364],{"class":274},"ccm-dashboard-form-actions",[36,1366,1298],{"class":270},[36,1368,1282],{"class":270},[36,1370,1371,1374,1377,1379,1381,1383,1386,1388],{"class":38,"line":75},[36,1372,1373],{"class":270},"                \u003C",[36,1375,1376],{"class":1278},"button",[36,1378,1293],{"class":355},[36,1380,317],{"class":270},[36,1382,1298],{"class":270},[36,1384,1385],{"class":274},"pull-left btn btn-primary",[36,1387,1298],{"class":270},[36,1389,1282],{"class":270},[36,1391,1392],{"class":38,"line":81},[36,1393,1394],{"class":263},"                    一覧へ戻る\n",[36,1396,1397,1400,1402],{"class":38,"line":87},[36,1398,1399],{"class":270},"                \u003C\u002F",[36,1401,1376],{"class":1278},[36,1403,1282],{"class":270},[36,1405,1406,1408,1410,1413,1415,1417,1420,1422,1424,1426,1428,1431,1433],{"class":38,"line":92},[36,1407,1373],{"class":270},[36,1409,807],{"class":1278},[36,1411,1412],{"class":355}," href",[36,1414,317],{"class":270},[36,1416,1298],{"class":270},[36,1418,1419],{"class":274},"#",[36,1421,1298],{"class":270},[36,1423,1293],{"class":355},[36,1425,317],{"class":270},[36,1427,1298],{"class":270},[36,1429,1430],{"class":274},"pull-right btn btn-primary",[36,1432,1298],{"class":270},[36,1434,1282],{"class":270},[36,1436,1437],{"class":38,"line":98},[36,1438,1439],{"class":263},"                    登録\n",[36,1441,1442,1444,1446],{"class":38,"line":104},[36,1443,1399],{"class":270},[36,1445,807],{"class":1278},[36,1447,1282],{"class":270},[36,1449,1450,1453,1455],{"class":38,"line":481},[36,1451,1452],{"class":270},"            \u003C\u002F",[36,1454,1290],{"class":1278},[36,1456,1282],{"class":270},[36,1458,1459,1462,1464],{"class":38,"line":487},[36,1460,1461],{"class":270},"        \u003C\u002F",[36,1463,1290],{"class":1278},[36,1465,1282],{"class":270},[36,1467,1468,1471,1473],{"class":38,"line":493},[36,1469,1470],{"class":270},"    \u003C\u002F",[36,1472,1290],{"class":1278},[36,1474,1282],{"class":270},[36,1476,1477,1479,1481],{"class":38,"line":499},[36,1478,1321],{"class":270},[36,1480,1279],{"class":1278},[36,1482,1282],{"class":270},[36,1484,1485],{"class":38,"line":505},[36,1486,55],{"emptyLinePlaceholder":54},[36,1488,1489,1491,1494],{"class":38,"line":511},[36,1490,1275],{"class":270},[36,1492,1493],{"class":1278},"script",[36,1495,1282],{"class":270},[36,1497,1498,1501,1504],{"class":38,"line":517},[36,1499,1500],{"class":259},"export",[36,1502,1503],{"class":259}," default",[36,1505,1506],{"class":270}," {\n",[36,1508,1509,1512,1514,1516,1519,1521],{"class":38,"line":523},[36,1510,1511],{"class":1278},"    name",[36,1513,348],{"class":270},[36,1515,382],{"class":270},[36,1517,1518],{"class":274},"albumForm",[36,1520,382],{"class":270},[36,1522,364],{"class":270},[36,1524,1525,1528,1530,1533,1535,1538,1540],{"class":38,"line":529},[36,1526,1527],{"class":1278},"    props",[36,1529,348],{"class":270},[36,1531,1532],{"class":263},"[",[36,1534,382],{"class":270},[36,1536,1537],{"class":274},"isEdit",[36,1539,382],{"class":270},[36,1541,1542],{"class":263},"]\n",[36,1544,1545],{"class":38,"line":534},[36,1546,599],{"class":270},[36,1548,1549,1551,1553],{"class":38,"line":540},[36,1550,1321],{"class":270},[36,1552,1493],{"class":1278},[36,1554,1282],{"class":270},[11,1556,1557],{},"そしてadd.vueでこのform.vueを読み込んで",[26,1559,1562],{"className":1266,"code":1560,"filename":1561,"language":275,"meta":31,"style":31},"\u003Ctemplate>\n    \u003CAlbumForm :isEdit=\"false\"\u002F>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport AlbumForm from '.\u002Fcomponents\u002Fform';\nexport default {\n    name:'add',\n    components:{AlbumForm}\n}\n\u003C\u002Fscript>\n","app.vue",[33,1563,1564,1572,1594,1602,1606,1614,1633,1641,1656,1668,1672],{"__ignoreMap":31},[36,1565,1566,1568,1570],{"class":38,"line":39},[36,1567,1275],{"class":270},[36,1569,1279],{"class":1278},[36,1571,1282],{"class":270},[36,1573,1574,1576,1579,1582,1584,1586,1589,1591],{"class":38,"line":45},[36,1575,1287],{"class":270},[36,1577,1578],{"class":1278},"AlbumForm",[36,1580,1581],{"class":355}," :isEdit",[36,1583,317],{"class":270},[36,1585,1298],{"class":270},[36,1587,1588],{"class":274},"false",[36,1590,1298],{"class":270},[36,1592,1593],{"class":270},"\u002F>\n",[36,1595,1596,1598,1600],{"class":38,"line":51},[36,1597,1321],{"class":270},[36,1599,1279],{"class":1278},[36,1601,1282],{"class":270},[36,1603,1604],{"class":38,"line":58},[36,1605,55],{"emptyLinePlaceholder":54},[36,1607,1608,1610,1612],{"class":38,"line":64},[36,1609,1275],{"class":270},[36,1611,1493],{"class":1278},[36,1613,1282],{"class":270},[36,1615,1616,1618,1621,1623,1625,1628,1630],{"class":38,"line":70},[36,1617,260],{"class":259},[36,1619,1620],{"class":263}," AlbumForm ",[36,1622,267],{"class":259},[36,1624,271],{"class":270},[36,1626,1627],{"class":274},".\u002Fcomponents\u002Fform",[36,1629,382],{"class":270},[36,1631,1632],{"class":270},";\n",[36,1634,1635,1637,1639],{"class":38,"line":75},[36,1636,1500],{"class":259},[36,1638,1503],{"class":259},[36,1640,1506],{"class":270},[36,1642,1643,1645,1647,1649,1652,1654],{"class":38,"line":81},[36,1644,1511],{"class":1278},[36,1646,348],{"class":270},[36,1648,382],{"class":270},[36,1650,1651],{"class":274},"add",[36,1653,382],{"class":270},[36,1655,364],{"class":270},[36,1657,1658,1661,1664,1666],{"class":38,"line":87},[36,1659,1660],{"class":1278},"    components",[36,1662,1663],{"class":270},":{",[36,1665,1578],{"class":263},[36,1667,599],{"class":270},[36,1669,1670],{"class":38,"line":92},[36,1671,599],{"class":270},[36,1673,1674,1676,1678],{"class":38,"line":98},[36,1675,1321],{"class":270},[36,1677,1493],{"class":1278},[36,1679,1282],{"class":270},[11,1681,1682,1684,1685,1687],{},[33,1683,237],{},"にて",[33,1686,241],{},"の要素にマウントする様にします。",[26,1689,1691],{"className":249,"code":1690,"filename":237,"language":252,"meta":31,"style":31},"import Vue from 'vue'\nimport Add from '.\u002Fadd.vue'\n\nVue.config.productionTip = false\n\nnew Vue({\n  render: h => h(Add),\n}).$mount('#add')\n",[33,1692,1693,1707,1723,1727,1743,1747,1757,1774],{"__ignoreMap":31},[36,1694,1695,1697,1699,1701,1703,1705],{"class":38,"line":39},[36,1696,260],{"class":259},[36,1698,264],{"class":263},[36,1700,267],{"class":259},[36,1702,271],{"class":270},[36,1704,275],{"class":274},[36,1706,278],{"class":270},[36,1708,1709,1711,1714,1716,1718,1721],{"class":38,"line":45},[36,1710,260],{"class":259},[36,1712,1713],{"class":263}," Add ",[36,1715,267],{"class":259},[36,1717,271],{"class":270},[36,1719,1720],{"class":274},".\u002Fadd.vue",[36,1722,278],{"class":270},[36,1724,1725],{"class":38,"line":51},[36,1726,55],{"emptyLinePlaceholder":54},[36,1728,1729,1731,1733,1735,1737,1739,1741],{"class":38,"line":58},[36,1730,303],{"class":263},[36,1732,306],{"class":270},[36,1734,309],{"class":263},[36,1736,306],{"class":270},[36,1738,314],{"class":263},[36,1740,317],{"class":270},[36,1742,321],{"class":320},[36,1744,1745],{"class":38,"line":64},[36,1746,55],{"emptyLinePlaceholder":54},[36,1748,1749,1751,1753,1755],{"class":38,"line":70},[36,1750,330],{"class":270},[36,1752,334],{"class":333},[36,1754,337],{"class":263},[36,1756,340],{"class":270},[36,1758,1759,1761,1763,1765,1767,1769,1772],{"class":38,"line":75},[36,1760,345],{"class":333},[36,1762,348],{"class":270},[36,1764,352],{"class":351},[36,1766,356],{"class":355},[36,1768,352],{"class":333},[36,1770,1771],{"class":263},"(Add)",[36,1773,364],{"class":270},[36,1775,1776,1778,1780,1782,1784,1786,1788,1791,1793],{"class":38,"line":81},[36,1777,369],{"class":270},[36,1779,372],{"class":263},[36,1781,306],{"class":270},[36,1783,377],{"class":333},[36,1785,337],{"class":263},[36,1787,382],{"class":270},[36,1789,1790],{"class":274},"#add",[36,1792,382],{"class":270},[36,1794,390],{"class":263},[11,1796,1797,1798,1801],{},"こうしてビルドをしてみましょう。そして",[33,1799,1800],{},"\u002Fdashboard\u002Fvuetest\u002Fadd","へ移動してみると",[112,1803],{":src":1804,":width":115},"'_mix\u002Fsch-2020-08-26-22.48.54-768x529.png'",[11,1806,1807,1808,1810,1811,1813,1814,1816],{},"しっかりと",[33,1809,241],{},"に",[33,1812,1268],{},"がレンダリングされました。ではこの",[33,1815,1268],{},"にガシガシとフォームUIを作っていきましょう！",[18,1818,1819],{"id":1819},"まずはタイトルを入力するだけのものを作成",[11,1821,1822],{},"最終的なフォームにはリッチテキストエディタとファイルセレクターなど、concrete5で用いられているフォームをvueで実装したいと思います。しかし、その２つはなかなか曲者で今回の記事で説明すると長くなるので次回に話します。",[11,1824,1825],{},"まずはvueとPHP(concrete5)でどう連携させてDBにデータを挿入するかの全体的な流れについて説明するとともに、タイトル部分（プレーンテキスト）を追加できる様にしていきましょう。",[139,1827,1829],{"id":1828},"postでバックに値を送る","POSTでバックに値を送る",[11,1831,1832,1833,1836,1837,1840,1841,1843],{},"vueで構築したUIで入力された値はどうやってバックに渡すか？簡単です。フォームを作る時の様に",[33,1834,1835],{},"input","を",[33,1838,1839],{},"\u003Cform method=\"post\">\u003C\u002Fform>","で囲んであげて、送信用のsubmitボタンを作るだけです。今回のパッケージではPOSTの値をAjaxとかで送るのでなく、普通にsubmitでサーバーに送信する様にしました。以下の様に",[33,1842,1268],{},"を変えます。",[26,1845,1847],{"className":1266,"code":1846,"filename":1268,"language":275,"meta":31,"style":31},"\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Ch3>アルバム新規追加\u003C\u002Fh3>\n        \u003Chr>\n        \u003Cform method=\"post\">\n            \u003Clabel for=\"title\" class=\"control-label\">アルバムタイトル\u003C\u002Flabel>\n            \u003Cinput type=\"text\" name=\"title\" class=\"form-control ccm-input-text\" v-model=\"title\">\n\n            \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n                \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                    \u003Cbutton class=\"pull-left btn btn-primary\">\n                        一覧へ戻る\n                    \u003C\u002Fbutton>\n                    \u003Cinput value=\"登録\" type=\"submit\" class=\"pull-right btn btn-primary\">\n                \u003C\u002Fdiv>\n            \u003C\u002Fdiv>\n        \u003C\u002Fform>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n    name:'albumForm',\n    props:['isEdit'],\n    data(){\n        return{\n            title:''\n        }\n    }\n}\n\u003C\u002Fscript>\n",[33,1848,1849,1857,1875,1892,1901,1922,1963,2015,2019,2037,2055,2074,2079,2088,2129,2137,2145,2153,2161,2169,2173,2181,2189,2203,2222,2230,2237,2247,2252,2256,2260],{"__ignoreMap":31},[36,1850,1851,1853,1855],{"class":38,"line":39},[36,1852,1275],{"class":270},[36,1854,1279],{"class":1278},[36,1856,1282],{"class":270},[36,1858,1859,1861,1863,1865,1867,1869,1871,1873],{"class":38,"line":45},[36,1860,1287],{"class":270},[36,1862,1290],{"class":1278},[36,1864,1293],{"class":355},[36,1866,317],{"class":270},[36,1868,1298],{"class":270},[36,1870,1301],{"class":274},[36,1872,1298],{"class":270},[36,1874,1282],{"class":270},[36,1876,1877,1879,1881,1883,1886,1888,1890],{"class":38,"line":51},[36,1878,1310],{"class":270},[36,1880,139],{"class":1278},[36,1882,1315],{"class":270},[36,1884,1885],{"class":263},"アルバム新規追加",[36,1887,1321],{"class":270},[36,1889,139],{"class":1278},[36,1891,1282],{"class":270},[36,1893,1894,1896,1899],{"class":38,"line":58},[36,1895,1310],{"class":270},[36,1897,1898],{"class":1278},"hr",[36,1900,1282],{"class":270},[36,1902,1903,1905,1908,1911,1913,1915,1918,1920],{"class":38,"line":64},[36,1904,1310],{"class":270},[36,1906,1907],{"class":1278},"form",[36,1909,1910],{"class":355}," method",[36,1912,317],{"class":270},[36,1914,1298],{"class":270},[36,1916,1917],{"class":274},"post",[36,1919,1298],{"class":270},[36,1921,1282],{"class":270},[36,1923,1924,1926,1929,1932,1934,1936,1939,1941,1943,1945,1947,1950,1952,1954,1957,1959,1961],{"class":38,"line":70},[36,1925,1353],{"class":270},[36,1927,1928],{"class":1278},"label",[36,1930,1931],{"class":355}," for",[36,1933,317],{"class":270},[36,1935,1298],{"class":270},[36,1937,1938],{"class":274},"title",[36,1940,1298],{"class":270},[36,1942,1293],{"class":355},[36,1944,317],{"class":270},[36,1946,1298],{"class":270},[36,1948,1949],{"class":274},"control-label",[36,1951,1298],{"class":270},[36,1953,1315],{"class":270},[36,1955,1956],{"class":263},"アルバムタイトル",[36,1958,1321],{"class":270},[36,1960,1928],{"class":1278},[36,1962,1282],{"class":270},[36,1964,1965,1967,1969,1972,1974,1976,1978,1980,1983,1985,1987,1989,1991,1993,1995,1997,2000,2002,2005,2007,2009,2011,2013],{"class":38,"line":75},[36,1966,1353],{"class":270},[36,1968,1835],{"class":1278},[36,1970,1971],{"class":355}," type",[36,1973,317],{"class":270},[36,1975,1298],{"class":270},[36,1977,163],{"class":274},[36,1979,1298],{"class":270},[36,1981,1982],{"class":355}," name",[36,1984,317],{"class":270},[36,1986,1298],{"class":270},[36,1988,1938],{"class":274},[36,1990,1298],{"class":270},[36,1992,1293],{"class":355},[36,1994,317],{"class":270},[36,1996,1298],{"class":270},[36,1998,1999],{"class":274},"form-control ccm-input-text",[36,2001,1298],{"class":270},[36,2003,2004],{"class":355}," v-model",[36,2006,317],{"class":270},[36,2008,1298],{"class":270},[36,2010,1938],{"class":274},[36,2012,1298],{"class":270},[36,2014,1282],{"class":270},[36,2016,2017],{"class":38,"line":81},[36,2018,55],{"emptyLinePlaceholder":54},[36,2020,2021,2023,2025,2027,2029,2031,2033,2035],{"class":38,"line":87},[36,2022,1353],{"class":270},[36,2024,1290],{"class":1278},[36,2026,1293],{"class":355},[36,2028,317],{"class":270},[36,2030,1298],{"class":270},[36,2032,1344],{"class":274},[36,2034,1298],{"class":270},[36,2036,1282],{"class":270},[36,2038,2039,2041,2043,2045,2047,2049,2051,2053],{"class":38,"line":92},[36,2040,1373],{"class":270},[36,2042,1290],{"class":1278},[36,2044,1293],{"class":355},[36,2046,317],{"class":270},[36,2048,1298],{"class":270},[36,2050,1364],{"class":274},[36,2052,1298],{"class":270},[36,2054,1282],{"class":270},[36,2056,2057,2060,2062,2064,2066,2068,2070,2072],{"class":38,"line":98},[36,2058,2059],{"class":270},"                    \u003C",[36,2061,1376],{"class":1278},[36,2063,1293],{"class":355},[36,2065,317],{"class":270},[36,2067,1298],{"class":270},[36,2069,1385],{"class":274},[36,2071,1298],{"class":270},[36,2073,1282],{"class":270},[36,2075,2076],{"class":38,"line":104},[36,2077,2078],{"class":263},"                        一覧へ戻る\n",[36,2080,2081,2084,2086],{"class":38,"line":481},[36,2082,2083],{"class":270},"                    \u003C\u002F",[36,2085,1376],{"class":1278},[36,2087,1282],{"class":270},[36,2089,2090,2092,2094,2097,2099,2101,2104,2106,2108,2110,2112,2115,2117,2119,2121,2123,2125,2127],{"class":38,"line":487},[36,2091,2059],{"class":270},[36,2093,1835],{"class":1278},[36,2095,2096],{"class":355}," value",[36,2098,317],{"class":270},[36,2100,1298],{"class":270},[36,2102,2103],{"class":274},"登録",[36,2105,1298],{"class":270},[36,2107,1971],{"class":355},[36,2109,317],{"class":270},[36,2111,1298],{"class":270},[36,2113,2114],{"class":274},"submit",[36,2116,1298],{"class":270},[36,2118,1293],{"class":355},[36,2120,317],{"class":270},[36,2122,1298],{"class":270},[36,2124,1430],{"class":274},[36,2126,1298],{"class":270},[36,2128,1282],{"class":270},[36,2130,2131,2133,2135],{"class":38,"line":493},[36,2132,1399],{"class":270},[36,2134,1290],{"class":1278},[36,2136,1282],{"class":270},[36,2138,2139,2141,2143],{"class":38,"line":499},[36,2140,1452],{"class":270},[36,2142,1290],{"class":1278},[36,2144,1282],{"class":270},[36,2146,2147,2149,2151],{"class":38,"line":505},[36,2148,1461],{"class":270},[36,2150,1907],{"class":1278},[36,2152,1282],{"class":270},[36,2154,2155,2157,2159],{"class":38,"line":511},[36,2156,1470],{"class":270},[36,2158,1290],{"class":1278},[36,2160,1282],{"class":270},[36,2162,2163,2165,2167],{"class":38,"line":517},[36,2164,1321],{"class":270},[36,2166,1279],{"class":1278},[36,2168,1282],{"class":270},[36,2170,2171],{"class":38,"line":523},[36,2172,55],{"emptyLinePlaceholder":54},[36,2174,2175,2177,2179],{"class":38,"line":529},[36,2176,1275],{"class":270},[36,2178,1493],{"class":1278},[36,2180,1282],{"class":270},[36,2182,2183,2185,2187],{"class":38,"line":534},[36,2184,1500],{"class":259},[36,2186,1503],{"class":259},[36,2188,1506],{"class":270},[36,2190,2191,2193,2195,2197,2199,2201],{"class":38,"line":540},[36,2192,1511],{"class":1278},[36,2194,348],{"class":270},[36,2196,382],{"class":270},[36,2198,1518],{"class":274},[36,2200,382],{"class":270},[36,2202,364],{"class":270},[36,2204,2205,2207,2209,2211,2213,2215,2217,2220],{"class":38,"line":545},[36,2206,1527],{"class":1278},[36,2208,348],{"class":270},[36,2210,1532],{"class":263},[36,2212,382],{"class":270},[36,2214,1537],{"class":274},[36,2216,382],{"class":270},[36,2218,2219],{"class":263},"]",[36,2221,364],{"class":270},[36,2223,2224,2227],{"class":38,"line":550},[36,2225,2226],{"class":1278},"    data",[36,2228,2229],{"class":270},"(){\n",[36,2231,2232,2235],{"class":38,"line":555},[36,2233,2234],{"class":259},"        return",[36,2236,340],{"class":270},[36,2238,2239,2242,2244],{"class":38,"line":560},[36,2240,2241],{"class":1278},"            title",[36,2243,348],{"class":270},[36,2245,2246],{"class":270},"''\n",[36,2248,2249],{"class":38,"line":566},[36,2250,2251],{"class":270},"        }\n",[36,2253,2254],{"class":38,"line":572},[36,2255,587],{"class":270},[36,2257,2258],{"class":38,"line":578},[36,2259,599],{"class":270},[36,2261,2262,2264,2266],{"class":38,"line":584},[36,2263,1321],{"class":270},[36,2265,1493],{"class":1278},[36,2267,1282],{"class":270},[139,2269,2270],{"id":2270},"フロントバリデーションを実装",[11,2272,2273],{},"フォームから入力された値をバリデーションチェックします。しかし今回はせっかくvueを使っているのでフロントでバリデーションをしてあげましょう。例えばtitleが空でないかをチェックする場合以下の様にします。",[26,2275,2277],{"className":1266,"code":2276,"filename":1268,"language":275,"meta":31,"style":31},"\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Ch3>アルバム新規追加\u003C\u002Fh3>\n        \u003Chr>\n        \u003Cform method=\"post\" @submit=\"checkForm\">\n            \u003Clabel for=\"title\" class=\"control-label\">アルバムタイトル\u003C\u002Flabel>\n            \u003Cinput type=\"text\" name=\"title\" class=\"form-control ccm-input-text\" v-model=\"title\">\n            \u003Cp class=\"text-danger\" v-if=\"errTitle.length>0\">{{errTitle}}\u003C\u002Fp>\n\n            \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n                \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                    \u003Cbutton class=\"pull-left btn btn-primary\">\n                        一覧へ戻る\n                    \u003C\u002Fbutton>\n                    \u003Cinput value=\"登録\" type=\"submit\" class=\"pull-right btn btn-primary\">\n                \u003C\u002Fdiv>\n            \u003C\u002Fdiv>\n        \u003C\u002Fform>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    name:'albumForm',\n    props:['isEdit'],\n    data(){\n        return{\n            title:'',\n            errTitle:''\n        }\n    },\n    methods:{\n        checkForm($event){\n            if(this.title.length >0){\n                return true;\n            }else{\n                $event.preventDefault();\n                ConcreteAlert.error({\n                    title:'入力項目に誤りがあります。',\n                    message:'アルバムタイトルが入力されていません。',\n                    delay:5000\n                })\n                this.errTitle = \"タイトルを入力してください。\"\n            }\n        }\n    }\n}\n\u003C\u002Fscript>\n",[33,2278,2279,2287,2305,2321,2329,2359,2395,2443,2483,2487,2505,2523,2541,2545,2553,2591,2599,2607,2615,2623,2631,2639,2647,2661,2679,2685,2691,2702,2711,2715,2720,2728,2741,2769,2779,2789,2804,2818,2834,2850,2860,2867,2887,2892,2896,2900,2905],{"__ignoreMap":31},[36,2280,2281,2283,2285],{"class":38,"line":39},[36,2282,1275],{"class":270},[36,2284,1279],{"class":1278},[36,2286,1282],{"class":270},[36,2288,2289,2291,2293,2295,2297,2299,2301,2303],{"class":38,"line":45},[36,2290,1287],{"class":270},[36,2292,1290],{"class":1278},[36,2294,1293],{"class":355},[36,2296,317],{"class":270},[36,2298,1298],{"class":270},[36,2300,1301],{"class":274},[36,2302,1298],{"class":270},[36,2304,1282],{"class":270},[36,2306,2307,2309,2311,2313,2315,2317,2319],{"class":38,"line":51},[36,2308,1310],{"class":270},[36,2310,139],{"class":1278},[36,2312,1315],{"class":270},[36,2314,1885],{"class":263},[36,2316,1321],{"class":270},[36,2318,139],{"class":1278},[36,2320,1282],{"class":270},[36,2322,2323,2325,2327],{"class":38,"line":58},[36,2324,1310],{"class":270},[36,2326,1898],{"class":1278},[36,2328,1282],{"class":270},[36,2330,2331,2333,2335,2337,2339,2341,2343,2345,2348,2350,2352,2355,2357],{"class":38,"line":64},[36,2332,1310],{"class":270},[36,2334,1907],{"class":1278},[36,2336,1910],{"class":355},[36,2338,317],{"class":270},[36,2340,1298],{"class":270},[36,2342,1917],{"class":274},[36,2344,1298],{"class":270},[36,2346,2347],{"class":355}," @submit",[36,2349,317],{"class":270},[36,2351,1298],{"class":270},[36,2353,2354],{"class":274},"checkForm",[36,2356,1298],{"class":270},[36,2358,1282],{"class":270},[36,2360,2361,2363,2365,2367,2369,2371,2373,2375,2377,2379,2381,2383,2385,2387,2389,2391,2393],{"class":38,"line":70},[36,2362,1353],{"class":270},[36,2364,1928],{"class":1278},[36,2366,1931],{"class":355},[36,2368,317],{"class":270},[36,2370,1298],{"class":270},[36,2372,1938],{"class":274},[36,2374,1298],{"class":270},[36,2376,1293],{"class":355},[36,2378,317],{"class":270},[36,2380,1298],{"class":270},[36,2382,1949],{"class":274},[36,2384,1298],{"class":270},[36,2386,1315],{"class":270},[36,2388,1956],{"class":263},[36,2390,1321],{"class":270},[36,2392,1928],{"class":1278},[36,2394,1282],{"class":270},[36,2396,2397,2399,2401,2403,2405,2407,2409,2411,2413,2415,2417,2419,2421,2423,2425,2427,2429,2431,2433,2435,2437,2439,2441],{"class":38,"line":75},[36,2398,1353],{"class":270},[36,2400,1835],{"class":1278},[36,2402,1971],{"class":355},[36,2404,317],{"class":270},[36,2406,1298],{"class":270},[36,2408,163],{"class":274},[36,2410,1298],{"class":270},[36,2412,1982],{"class":355},[36,2414,317],{"class":270},[36,2416,1298],{"class":270},[36,2418,1938],{"class":274},[36,2420,1298],{"class":270},[36,2422,1293],{"class":355},[36,2424,317],{"class":270},[36,2426,1298],{"class":270},[36,2428,1999],{"class":274},[36,2430,1298],{"class":270},[36,2432,2004],{"class":355},[36,2434,317],{"class":270},[36,2436,1298],{"class":270},[36,2438,1938],{"class":274},[36,2440,1298],{"class":270},[36,2442,1282],{"class":270},[36,2444,2445,2447,2449,2451,2453,2455,2458,2460,2463,2465,2467,2470,2472,2474,2477,2479,2481],{"class":38,"line":81},[36,2446,1353],{"class":270},[36,2448,11],{"class":1278},[36,2450,1293],{"class":355},[36,2452,317],{"class":270},[36,2454,1298],{"class":270},[36,2456,2457],{"class":274},"text-danger",[36,2459,1298],{"class":270},[36,2461,2462],{"class":355}," v-if",[36,2464,317],{"class":270},[36,2466,1298],{"class":270},[36,2468,2469],{"class":274},"errTitle.length>0",[36,2471,1298],{"class":270},[36,2473,1315],{"class":270},[36,2475,2476],{"class":263},"{{errTitle}}",[36,2478,1321],{"class":270},[36,2480,11],{"class":1278},[36,2482,1282],{"class":270},[36,2484,2485],{"class":38,"line":87},[36,2486,55],{"emptyLinePlaceholder":54},[36,2488,2489,2491,2493,2495,2497,2499,2501,2503],{"class":38,"line":92},[36,2490,1353],{"class":270},[36,2492,1290],{"class":1278},[36,2494,1293],{"class":355},[36,2496,317],{"class":270},[36,2498,1298],{"class":270},[36,2500,1344],{"class":274},[36,2502,1298],{"class":270},[36,2504,1282],{"class":270},[36,2506,2507,2509,2511,2513,2515,2517,2519,2521],{"class":38,"line":98},[36,2508,1373],{"class":270},[36,2510,1290],{"class":1278},[36,2512,1293],{"class":355},[36,2514,317],{"class":270},[36,2516,1298],{"class":270},[36,2518,1364],{"class":274},[36,2520,1298],{"class":270},[36,2522,1282],{"class":270},[36,2524,2525,2527,2529,2531,2533,2535,2537,2539],{"class":38,"line":104},[36,2526,2059],{"class":270},[36,2528,1376],{"class":1278},[36,2530,1293],{"class":355},[36,2532,317],{"class":270},[36,2534,1298],{"class":270},[36,2536,1385],{"class":274},[36,2538,1298],{"class":270},[36,2540,1282],{"class":270},[36,2542,2543],{"class":38,"line":481},[36,2544,2078],{"class":263},[36,2546,2547,2549,2551],{"class":38,"line":487},[36,2548,2083],{"class":270},[36,2550,1376],{"class":1278},[36,2552,1282],{"class":270},[36,2554,2555,2557,2559,2561,2563,2565,2567,2569,2571,2573,2575,2577,2579,2581,2583,2585,2587,2589],{"class":38,"line":493},[36,2556,2059],{"class":270},[36,2558,1835],{"class":1278},[36,2560,2096],{"class":355},[36,2562,317],{"class":270},[36,2564,1298],{"class":270},[36,2566,2103],{"class":274},[36,2568,1298],{"class":270},[36,2570,1971],{"class":355},[36,2572,317],{"class":270},[36,2574,1298],{"class":270},[36,2576,2114],{"class":274},[36,2578,1298],{"class":270},[36,2580,1293],{"class":355},[36,2582,317],{"class":270},[36,2584,1298],{"class":270},[36,2586,1430],{"class":274},[36,2588,1298],{"class":270},[36,2590,1282],{"class":270},[36,2592,2593,2595,2597],{"class":38,"line":499},[36,2594,1399],{"class":270},[36,2596,1290],{"class":1278},[36,2598,1282],{"class":270},[36,2600,2601,2603,2605],{"class":38,"line":505},[36,2602,1452],{"class":270},[36,2604,1290],{"class":1278},[36,2606,1282],{"class":270},[36,2608,2609,2611,2613],{"class":38,"line":511},[36,2610,1461],{"class":270},[36,2612,1907],{"class":1278},[36,2614,1282],{"class":270},[36,2616,2617,2619,2621],{"class":38,"line":517},[36,2618,1470],{"class":270},[36,2620,1290],{"class":1278},[36,2622,1282],{"class":270},[36,2624,2625,2627,2629],{"class":38,"line":523},[36,2626,1321],{"class":270},[36,2628,1279],{"class":1278},[36,2630,1282],{"class":270},[36,2632,2633,2635,2637],{"class":38,"line":529},[36,2634,1275],{"class":270},[36,2636,1493],{"class":1278},[36,2638,1282],{"class":270},[36,2640,2641,2643,2645],{"class":38,"line":534},[36,2642,1500],{"class":259},[36,2644,1503],{"class":259},[36,2646,1506],{"class":270},[36,2648,2649,2651,2653,2655,2657,2659],{"class":38,"line":540},[36,2650,1511],{"class":1278},[36,2652,348],{"class":270},[36,2654,382],{"class":270},[36,2656,1518],{"class":274},[36,2658,382],{"class":270},[36,2660,364],{"class":270},[36,2662,2663,2665,2667,2669,2671,2673,2675,2677],{"class":38,"line":545},[36,2664,1527],{"class":1278},[36,2666,348],{"class":270},[36,2668,1532],{"class":263},[36,2670,382],{"class":270},[36,2672,1537],{"class":274},[36,2674,382],{"class":270},[36,2676,2219],{"class":263},[36,2678,364],{"class":270},[36,2680,2681,2683],{"class":38,"line":550},[36,2682,2226],{"class":1278},[36,2684,2229],{"class":270},[36,2686,2687,2689],{"class":38,"line":555},[36,2688,2234],{"class":259},[36,2690,340],{"class":270},[36,2692,2693,2695,2697,2700],{"class":38,"line":560},[36,2694,2241],{"class":1278},[36,2696,348],{"class":270},[36,2698,2699],{"class":270},"''",[36,2701,364],{"class":270},[36,2703,2704,2707,2709],{"class":38,"line":566},[36,2705,2706],{"class":1278},"            errTitle",[36,2708,348],{"class":270},[36,2710,2246],{"class":270},[36,2712,2713],{"class":38,"line":572},[36,2714,2251],{"class":270},[36,2716,2717],{"class":38,"line":578},[36,2718,2719],{"class":270},"    },\n",[36,2721,2722,2725],{"class":38,"line":584},[36,2723,2724],{"class":1278},"    methods",[36,2726,2727],{"class":270},":{\n",[36,2729,2730,2733,2735,2738],{"class":38,"line":590},[36,2731,2732],{"class":1278},"        checkForm",[36,2734,337],{"class":270},[36,2736,2737],{"class":351},"$event",[36,2739,2740],{"class":270},"){\n",[36,2742,2743,2746,2748,2751,2753,2755,2758,2761,2765,2767],{"class":38,"line":596},[36,2744,2745],{"class":259},"            if",[36,2747,337],{"class":1278},[36,2749,2750],{"class":270},"this.",[36,2752,1938],{"class":263},[36,2754,306],{"class":270},[36,2756,2757],{"class":263},"length",[36,2759,2760],{"class":270}," >",[36,2762,2764],{"class":2763},"sx098","0",[36,2766,372],{"class":1278},[36,2768,340],{"class":270},[36,2770,2771,2774,2777],{"class":38,"line":1017},[36,2772,2773],{"class":259},"                return",[36,2775,2776],{"class":320}," true",[36,2778,1632],{"class":270},[36,2780,2781,2784,2787],{"class":38,"line":1023},[36,2782,2783],{"class":270},"            }",[36,2785,2786],{"class":259},"else",[36,2788,340],{"class":270},[36,2790,2791,2794,2796,2799,2802],{"class":38,"line":1028},[36,2792,2793],{"class":263},"                $event",[36,2795,306],{"class":270},[36,2797,2798],{"class":333},"preventDefault",[36,2800,2801],{"class":1278},"()",[36,2803,1632],{"class":270},[36,2805,2806,2809,2811,2814,2816],{"class":38,"line":1033},[36,2807,2808],{"class":263},"                ConcreteAlert",[36,2810,306],{"class":270},[36,2812,2813],{"class":333},"error",[36,2815,337],{"class":1278},[36,2817,340],{"class":270},[36,2819,2820,2823,2825,2827,2830,2832],{"class":38,"line":1038},[36,2821,2822],{"class":1278},"                    title",[36,2824,348],{"class":270},[36,2826,382],{"class":270},[36,2828,2829],{"class":274},"入力項目に誤りがあります。",[36,2831,382],{"class":270},[36,2833,364],{"class":270},[36,2835,2836,2839,2841,2843,2846,2848],{"class":38,"line":1043},[36,2837,2838],{"class":1278},"                    message",[36,2840,348],{"class":270},[36,2842,382],{"class":270},[36,2844,2845],{"class":274},"アルバムタイトルが入力されていません。",[36,2847,382],{"class":270},[36,2849,364],{"class":270},[36,2851,2852,2855,2857],{"class":38,"line":1048},[36,2853,2854],{"class":1278},"                    delay",[36,2856,348],{"class":270},[36,2858,2859],{"class":2763},"5000\n",[36,2861,2862,2865],{"class":38,"line":1053},[36,2863,2864],{"class":270},"                }",[36,2866,390],{"class":1278},[36,2868,2869,2872,2875,2878,2881,2884],{"class":38,"line":1058},[36,2870,2871],{"class":270},"                this.",[36,2873,2874],{"class":263},"errTitle",[36,2876,2877],{"class":270}," =",[36,2879,2880],{"class":270}," \"",[36,2882,2883],{"class":274},"タイトルを入力してください。",[36,2885,2886],{"class":270},"\"\n",[36,2888,2889],{"class":38,"line":1063},[36,2890,2891],{"class":270},"            }\n",[36,2893,2894],{"class":38,"line":1068},[36,2895,2251],{"class":270},[36,2897,2898],{"class":38,"line":1073},[36,2899,587],{"class":270},[36,2901,2903],{"class":38,"line":2902},46,[36,2904,599],{"class":270},[36,2906,2908,2910,2912],{"class":38,"line":2907},47,[36,2909,1321],{"class":270},[36,2911,1493],{"class":1278},[36,2913,1282],{"class":270},[11,2915,2916,2918,2919,2922,2923,2925,2926,2928],{},[33,2917,1907],{},"の箇所に",[33,2920,2921],{},"@submit=\"checkForm\"","というイベントを作成。これはこのformがsubmitされた際に",[33,2924,2354],{},"というメソッドを発火させるという意味です。そして",[33,2927,2354],{},"ではtitleの値が空かどうかを判断しています。",[11,2930,2931,2932,2935,2936,2938,2939,2942,2943,2946,2947,2949],{},"もし空でない場合は",[33,2933,2934],{},"return true","となって",[33,2937,2114],{},"が通って、サーバーへ値が送信されます。からの場合は",[33,2940,2941],{},"$event.preventDefault();","が実行されてsubmitされません。そして",[33,2944,2945],{},"ConcreteAlert.error","という8.4系から使用できるconcrete5のフラッシュメッセージのjsを出しています。（",[33,2948,2945],{},"は特に何も読み込まないでも使える）",[11,2951,2952],{},"空で「登録」を押すと以下の様になります。",[112,2954],{":src":2955,":width":115},"'_mix\u002Fsch-2020-08-27-0.07.18-768x531.png'",[11,2957,2958,2960],{},[33,2959,2941],{},"によってサーバーにデータは送信されず、ユーザーに対してエラーを表示できました。",[220,2962,2964],{"id":2963},"eslintがある時のchips","ESLintがある時のchips",[11,2966,2967,2970],{},[33,2968,2969],{},"ConcreteAlert"," はconcrete5が用意してくれた便利なフラッシュメッセージです。しかし、ESLint付きのvueCLI内で使用ようとすると、ビルド時にこの様に怒られます。",[26,2972,2975],{"className":2973,"code":2974,"language":163},[161],"ERROR  Failed to compile with 1 errors                                                                                                       23:50:16\n\n error  in .\u002Fsrc\u002Fcomponents\u002Fform.vue\n\nModule Error (from .\u002Fnode_modules\u002Feslint-loader\u002Findex.js):\n\n\u002FApplications\u002FMAMP\u002Fhtdocs\u002Fc5test\u002Fpackages\u002Fvuetest\u002Fjs\u002Fpackageui\u002Fsrc\u002Fcomponents\u002Fform.vue\n  40:17  error  'ConcreteAlert' is not defined  no-undef\n\n✖ 1 problem (1 error, 0 warnings)\n",[33,2976,2974],{"__ignoreMap":31},[11,2978,2979,2980,2982,2983,2986],{},"そうです。vueプロジェクト内には",[33,2981,2969],{}," を定義したjsファイルがない、というかconcreteが用意したjsを読み込めないのでこの様に怒られます。これだとビルドできないので",[33,2984,2985],{},"package.json","のeslintの設定に以下の記述をします。",[26,2988,2991],{"className":2989,"code":2990,"language":163},[161]," \"eslintConfig\": {\n　　\"globals\":{\n      \"ConcreteAlert\": true,\n    }\n },\n",[33,2992,2990],{"__ignoreMap":31},[11,2994,2995,2996,2998],{},"こうするとESLintは「ConcreteAlertってのはグローバルな奴なんだな〜。」と認識してくれて、実際にvueプロジェクト外にある",[33,2997,2969],{},"に対して怒らなくなります。",[18,3000,3001],{"id":3001},"バックエンド実装",[11,3003,3004],{},"vueを用いてまずはアルバムのタイトルだけを入力できるフォームを作りました。そしてこのタイトルをDBに挿入するまで行います。と言ってもシングルページコントローラーを以下の様に記述します。",[26,3006,3008],{"className":28,"code":3007,"filename":1102,"language":30,"meta":31,"style":31},"\u003C?php\nnamespace Concrete\\Package\\Vuetest\\Controller\\SinglePage\\Dashboard;\ndefined('C5_EXECUTE') or die('Access Denied.');\nuse \\Concrete\\Core\\Page\\Controller\\DashboardPageController;\nuse Concrete\\Core\\Routing\\Redirect;\nuse Concrete\\Core\\Http\\Request;\n\n\nuse Core;\nuse Database;\n\nclass Vuetest extends DashboardPageController\n{\n    public $packageHandle = 'vuetest';\n\n    public function on_start()\n    {\n        $this->requireAsset('package-vue-production');\n    }\n\n    public function view() {\n    }\n\n    public function add(){\n        if(Request::isPost() == true){\n            $title = $this->post('title');\n\n            if(empty($title)==false){\n                $db = Database::connection();\n                $db->executeQuery(\"START TRANSACTION\");\n                $db->executeQuery(\n                    'INSERT album SET `title`=?, `created`=now(), `modified`=now()',\n                    array($title)\n                );\n                $db->executeQuery(\"COMMIT\");\n                Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n            }else{\n                Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n            }\n\n        }else{\n            $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n        }\n    }\n}\n",[33,3009,3010,3014,3018,3022,3026,3031,3036,3040,3044,3049,3054,3058,3062,3066,3070,3074,3078,3082,3086,3090,3094,3098,3102,3106,3110,3115,3120,3124,3129,3134,3139,3144,3149,3154,3159,3164,3169,3174,3178,3182,3186,3191,3196,3200,3204],{"__ignoreMap":31},[36,3011,3012],{"class":38,"line":39},[36,3013,425],{},[36,3015,3016],{"class":38,"line":45},[36,3017,646],{},[36,3019,3020],{"class":38,"line":51},[36,3021,435],{},[36,3023,3024],{"class":38,"line":58},[36,3025,655],{},[36,3027,3028],{"class":38,"line":64},[36,3029,3030],{},"use Concrete\\Core\\Routing\\Redirect;\n",[36,3032,3033],{"class":38,"line":70},[36,3034,3035],{},"use Concrete\\Core\\Http\\Request;\n",[36,3037,3038],{"class":38,"line":75},[36,3039,55],{"emptyLinePlaceholder":54},[36,3041,3042],{"class":38,"line":81},[36,3043,55],{"emptyLinePlaceholder":54},[36,3045,3046],{"class":38,"line":87},[36,3047,3048],{},"use Core;\n",[36,3050,3051],{"class":38,"line":92},[36,3052,3053],{},"use Database;\n",[36,3055,3056],{"class":38,"line":98},[36,3057,55],{"emptyLinePlaceholder":54},[36,3059,3060],{"class":38,"line":104},[36,3061,664],{},[36,3063,3064],{"class":38,"line":481},[36,3065,340],{},[36,3067,3068],{"class":38,"line":487},[36,3069,673],{},[36,3071,3072],{"class":38,"line":493},[36,3073,55],{"emptyLinePlaceholder":54},[36,3075,3076],{"class":38,"line":499},[36,3077,478],{},[36,3079,3080],{"class":38,"line":505},[36,3081,484],{},[36,3083,3084],{"class":38,"line":511},[36,3085,687],{},[36,3087,3088],{"class":38,"line":517},[36,3089,587],{},[36,3091,3092],{"class":38,"line":523},[36,3093,55],{"emptyLinePlaceholder":54},[36,3095,3096],{"class":38,"line":529},[36,3097,682],{},[36,3099,3100],{"class":38,"line":534},[36,3101,587],{},[36,3103,3104],{"class":38,"line":540},[36,3105,55],{"emptyLinePlaceholder":54},[36,3107,3108],{"class":38,"line":545},[36,3109,1168],{},[36,3111,3112],{"class":38,"line":550},[36,3113,3114],{},"        if(Request::isPost() == true){\n",[36,3116,3117],{"class":38,"line":555},[36,3118,3119],{},"            $title = $this->post('title');\n",[36,3121,3122],{"class":38,"line":560},[36,3123,55],{"emptyLinePlaceholder":54},[36,3125,3126],{"class":38,"line":566},[36,3127,3128],{},"            if(empty($title)==false){\n",[36,3130,3131],{"class":38,"line":572},[36,3132,3133],{},"                $db = Database::connection();\n",[36,3135,3136],{"class":38,"line":578},[36,3137,3138],{},"                $db->executeQuery(\"START TRANSACTION\");\n",[36,3140,3141],{"class":38,"line":584},[36,3142,3143],{},"                $db->executeQuery(\n",[36,3145,3146],{"class":38,"line":590},[36,3147,3148],{},"                    'INSERT album SET `title`=?, `created`=now(), `modified`=now()',\n",[36,3150,3151],{"class":38,"line":596},[36,3152,3153],{},"                    array($title)\n",[36,3155,3156],{"class":38,"line":1017},[36,3157,3158],{},"                );\n",[36,3160,3161],{"class":38,"line":1023},[36,3162,3163],{},"                $db->executeQuery(\"COMMIT\");\n",[36,3165,3166],{"class":38,"line":1028},[36,3167,3168],{},"                Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n",[36,3170,3171],{"class":38,"line":1033},[36,3172,3173],{},"            }else{\n",[36,3175,3176],{"class":38,"line":1038},[36,3177,3168],{},[36,3179,3180],{"class":38,"line":1043},[36,3181,2891],{},[36,3183,3184],{"class":38,"line":1048},[36,3185,55],{"emptyLinePlaceholder":54},[36,3187,3188],{"class":38,"line":1053},[36,3189,3190],{},"        }else{\n",[36,3192,3193],{"class":38,"line":1058},[36,3194,3195],{},"            $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n",[36,3197,3198],{"class":38,"line":1063},[36,3199,2251],{},[36,3201,3202],{"class":38,"line":1068},[36,3203,587],{},[36,3205,3206],{"class":38,"line":1073},[36,3207,599],{},[11,3209,3210,3212,3213,3216,3217,3220],{},[33,3211,1800],{}," でpostを送ると",[33,3214,3215],{},"add()","にて処理が行われます。",[33,3218,3219],{},"Request::isPost()","というメソッドを用いてリクエストがpostかどうかをチェックします。postであれば値をDBへ挿入するスクリプトを実行し、そうでなければ新規追加の画面を表示します。",[11,3222,3223,3226,3227,3230,3231,3234,3235,3238],{},[33,3224,3225],{},"DashboardPageController","配下では",[33,3228,3229],{},"$this->post('name')"," というメソッドで対応するname属性のinputの値を取得することができます！先ほどのフォームではタイトルの値を",[33,3232,3233],{},"name=\"title\"","としていたので",[33,3236,3237],{},"$title = $this->post('title');","で取得します",[139,3240,3242],{"id":3241},"chips-必ずバックエンドでもバリデーションを実装する","chips 必ずバックエンドでもバリデーションを実装する",[11,3244,3245],{},"よくみると下記の様にタイトルの値を検査しています。",[26,3247,3249],{"className":28,"code":3248,"filename":1102,"language":30,"meta":31,"style":31},"if(empty($title)==false){\n ...\n}\n",[33,3250,3251,3256,3261],{"__ignoreMap":31},[36,3252,3253],{"class":38,"line":39},[36,3254,3255],{},"if(empty($title)==false){\n",[36,3257,3258],{"class":38,"line":45},[36,3259,3260],{}," ...\n",[36,3262,3263],{"class":38,"line":51},[36,3264,599],{},[1290,3266,3270,3271],{"className":3267},[3268,3269],"alert","alert-danger","\n「フロントエンド でタイトルの値をバリデーションしたから別にやらなくても良くない？」というのは厳禁です。postで来た値は必ずバックエンドで同様にバリデーションをかけます。",[3272,3273,3274],"b",{},"なぜならブラウザのconsoleでフロントでの値は偽造することもでき、フロントエンドのバリデーションを不正にスルーできるからです。",[11,3276,3277],{},"vueで行っているバリデーションはあくまでユーザー補助、UX的な物でありセキュリティの観点からは言えばガバガバです。エンドユーザーが偽造ができないバックエンドであれば確実にバリデーションをすることができます。",[11,3279,3280],{},"dashbord配下は基本的にサイト管理者が触る物なので、不正な値を入れようとする人はいないと思いますが、フロントからpostされた値は基本的に信用しないスタイルを貫いた方が無難です。",[18,3282,3283],{"id":3283},"データを入れてみる",[11,3285,3286,3287,3289],{},"では早速使ってみましょう。",[33,3288,1800],{}," にアクセスするとタイトル入力フォームが出てきました。仮に「テスト」と入力。そして「登録」を押します。",[112,3291],{":src":3292,":width":115},"'_mix\u002Fsch-2020-08-27-0.48.59-768x203.png'",[11,3294,3295],{},"一覧のページにリダイレクトされました。ちゃんと挿入されたか、phpmyadminでみてみましょう。",[112,3297],{":src":3298,":width":750,":center":751},"'_mix\u002Fsch-2020-08-27-0.51.36-768x340.png'",[11,3300,3301],{},"いましたね。titleが「テスト」となっているので、正しくデータが入力されました。",[18,3303,3305],{"id":3304},"次回は","次回は…",[11,3307,3308],{},"以上がvueとバックエンド部分の一通りの実装でした。",[123,3310,3311,3314,3317],{},[126,3312,3313],{},"シングルページにvueのエントリーポイントを作る",[126,3315,3316],{},"エントリポイントにレンダリングされる様にコンポーネントを設定",[126,3318,3319],{},"jsをシングルページに読み込む",[11,3321,3322],{},"¥以上を意識すればconcrete5のシングルページに自由にvueを用いてUIを構築できます。あとはvueの使い方とバックエンドの設計を頑張るだけです。そして次回は編集画面と一覧画面の作成をしていきます。",[766,3324,3325],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}",{"title":31,"searchDepth":51,"depth":51,"links":3327},[3328,3331,3332,3335,3336,3342,3345,3346],{"id":819,"depth":45,"text":819,"children":3329},[3330],{"id":839,"depth":51,"text":840},{"id":849,"depth":45,"text":850},{"id":1082,"depth":45,"text":1083,"children":3333},[3334],{"id":1086,"depth":51,"text":1087},{"id":1248,"depth":45,"text":1248},{"id":1819,"depth":45,"text":1819,"children":3337},[3338,3339],{"id":1828,"depth":51,"text":1829},{"id":2270,"depth":51,"text":2270,"children":3340},[3341],{"id":2963,"depth":58,"text":2964},{"id":3001,"depth":45,"text":3001,"children":3343},[3344],{"id":3241,"depth":51,"text":3242},{"id":3283,"depth":45,"text":3283},{"id":3304,"depth":45,"text":3305},[783],"2020-08-27","oncrete5にVueCLIを使ってUIを構築する。データの登録。",{},{"title":800,"description":3349},"series\u002Fconcrete5vue-2",[793,794,275],"s28kXBmZtYl1vPtmgjcP0QiTjdZEL9Zwpvzi-377-0o",{"id":3356,"title":3357,"body":3358,"category":6691,"createdAt":6692,"description":6693,"extension":786,"index":51,"meta":6694,"navigation":54,"path":6695,"publish":54,"seo":6696,"series":790,"seriesTitle":785,"stem":6697,"tag":6698,"thumbnail":795,"updatedAt":796,"__hash__":6699},"series\u002Fseries\u002Fconcrete5vue-3.md","Concrete5にVueCLIを使ってUIを構築する。3【編集画面と一覧画面】",{"type":8,"value":3359,"toc":6668},[3360,3366,3369,3373,3380,3383,3387,3390,3395,3402,3468,3479,3486,3493,3498,3501,3874,3878,3882,3888,3965,3973,3980,3983,3986,4013,4020,4132,4138,4380,4383,4390,4405,4408,4415,4418,4421,4424,4524,4527,4530,4536,4698,4705,4708,4711,4714,4717,4720,4723,4726,4729,6040,6043,6055,6058,6061,6064,6068,6073,6205,6209,6212,6218,6244,6247,6503,6509,6512,6515,6518,6521,6524,6527,6530,6533,6536,6539,6542,6545,6548,6551,6554,6653,6656,6659,6662,6665],[11,3361,805,3362,3365],{},[807,3363,3364],{"href":809},"Concrete5にVueCLIを使ってUIを構築する 2","の記事の続きを書いていきます。前回の記事ではフォームの作成・登録まで行いました。この記事では登録したデータの編集とファイルマネージャーのvueコンポーネント化を行っていきます。",[11,3367,3368],{},"編集画面は追加画面とコンポーネントを共有し、データベースからAjaxでデータを取得してコンポーネントに代入をします。そして登録したデータの操作が行える一覧画面を作成します。",[18,3370,3372],{"id":3371},"編集画面のレンダーとajax設定","編集画面のレンダーとAjax設定",[11,3374,3375,3376,3379],{},"まずは編集画面から作成していきます。編集は追加と違ってデータベースからデータを取得して、初期値として当てはめる必要があります。PHPであれば",[33,3377,3378],{},"value=\"\u003C?php echo $data?>\"","みたいに挿入することで簡単に実現できますが、vueを使うとなれば一捻り必要です。",[11,3381,3382],{},"jsでフロントを構築する場合、基本的にDBのデータはAjaxを用いて再度サーバーにデータを要求します。concrete5でもAjaxとそのエントリーを実装することができます。まずエントリーの設定からやってみましょう。",[139,3384,3386],{"id":3385},"ajaxエントリーrest-apiの作成","Ajaxエントリー(REST API)の作成",[11,3388,3389],{},"今回はシングルページのコントローラーを用いてAjax用のエントリーを実装します。Ajaxでデータを取得する際は基本的に取得用のURLを作成して、そのURLに対してAjaxを飛ばしてJSONデータをレスポンスとして受け取るのが定石です。",[26,3391,3393],{"className":3392,"code":1094,"language":163},[161],[33,3394,1094],{"__ignoreMap":31},[11,3396,3397,3398,3401],{},"では ",[33,3399,3400],{},"vuetest\u002Fcontrollers\u002Fsingle_page\u002Fdashboard\u002Fvuetest.php"," に以下のように記述します。",[26,3403,3405],{"className":28,"code":3404,"filename":1102,"language":30,"meta":31,"style":31},"public function edit($id=null){\n    if($id==null) return Redirect::to('\u002Fdashboard\u002Fvuetest\u002F')->send();\n\n    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $result = $db->fetchAll('SELECT * FROM album WHERE ID = ?',array($id));\n        $db->Execute(\"COMMIT\");\n        return Core::make('helper\u002Fajax')->sendResult($result);\n    }\n\n    $this->render('\u002Fdashboard\u002Fvuetest\u002Fedit');\n}\n",[33,3406,3407,3412,3417,3421,3426,3431,3436,3441,3446,3451,3455,3459,3464],{"__ignoreMap":31},[36,3408,3409],{"class":38,"line":39},[36,3410,3411],{},"public function edit($id=null){\n",[36,3413,3414],{"class":38,"line":45},[36,3415,3416],{},"    if($id==null) return Redirect::to('\u002Fdashboard\u002Fvuetest\u002F')->send();\n",[36,3418,3419],{"class":38,"line":51},[36,3420,55],{"emptyLinePlaceholder":54},[36,3422,3423],{"class":38,"line":58},[36,3424,3425],{},"    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n",[36,3427,3428],{"class":38,"line":64},[36,3429,3430],{},"        $db = Database::connection();\n",[36,3432,3433],{"class":38,"line":70},[36,3434,3435],{},"        $db->Execute(\"START TRANSACTION\");\n",[36,3437,3438],{"class":38,"line":75},[36,3439,3440],{},"        $result = $db->fetchAll('SELECT * FROM album WHERE ID = ?',array($id));\n",[36,3442,3443],{"class":38,"line":81},[36,3444,3445],{},"        $db->Execute(\"COMMIT\");\n",[36,3447,3448],{"class":38,"line":87},[36,3449,3450],{},"        return Core::make('helper\u002Fajax')->sendResult($result);\n",[36,3452,3453],{"class":38,"line":92},[36,3454,587],{},[36,3456,3457],{"class":38,"line":98},[36,3458,55],{"emptyLinePlaceholder":54},[36,3460,3461],{"class":38,"line":104},[36,3462,3463],{},"    $this->render('\u002Fdashboard\u002Fvuetest\u002Fedit');\n",[36,3465,3466],{"class":38,"line":481},[36,3467,599],{},[11,3469,3470,3471,3474,3475,3478],{},"まずは編集画面を ",[33,3472,3473],{},"\u002Fdashboard\u002Fvuetest\u002Fedit"," というURLで表示できるようにします。このメソッドではパラメータがあるので ",[33,3476,3477],{},"\u002Fdashboard\u002Fvuetest\u002Fedit\u002F2"," のようなURLを送信できます。数字の部分はアルバムのDBでのIDとします。（アルバムID）",[11,3480,3481,3482,3485],{},"つまり",[33,3483,3484],{},"\u002Fdashboard\u002Fvuetest\u002Fedit\u002F"," にアルバムIDを加えて送信することで、指定したIDのデータを表示できるようにします。そしてリクエストがXMLHttpRequestつまり、AjaxであればデータJSONで返し、そうでなければ404を返すようにします。",[11,3487,3488,3489,3492],{},"リクエストの種別を限定することで、ブラウザなどでAjax専用の ",[33,3490,3491],{},"\u002Fdashboard\u002Fvuetest\u002FloadData"," というURLを叩いても404しか表示されません。",[1290,3494,3497],{"className":3495},[3268,3496],"alert-info","\nこのようなAPIを作成するときは、データを差し出してもいいユーザーなのかをチェックする必要があります。しかし今回のような管理画面配下のページ（dashboard）でルーティングする場合は特に気にする必要はありません。\n",[11,3499,3500],{},"\u002Fdashboard\u002F* 配下はリクエストからログインユーザーであるかをチェックしており、ログインユーザーでないリクエストの場合、ログインページのHTMLが返されます。実際にcurlで上記のURLを打ってみると",[26,3502,3506],{"className":3503,"code":3504,"language":3505,"meta":31,"style":31},"language-html shiki shiki-themes material-theme-ocean","\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Clink rel=\"stylesheet\" type=\"text\u002Fcss\" href=\"\u002Fconcrete\u002Fthemes\u002Fconcrete\u002Fmain.css\" \u002F>\n    \n\u003Ctitle>ログイン :: c5test\u003C\u002Ftitle>\n\n\u003Cmeta http-equiv=\"content-type\" content=\"text\u002Fhtml; charset=UTF-8\"\u002F>\n\u003Cmeta name=\"generator\" content=\"concrete5 - 8.5.4\"\u002F>\n\u003Clink rel=\"canonical\" href=\"http:\u002F\u002Flocalhost:8888\u002Flogin\">\n\u003Cscript type=\"text\u002Fjavascript\">\n    var CCM_DISPATCHER_FILENAME = \"\u002Findex.php\";\n    var CCM_CID = 174;\n    var CCM_EDIT_MODE = false;\n    var CCM_ARRANGE_MODE = false;\n    var CCM_IMAGE_PATH = \"\u002Fconcrete\u002Fimages\";\n    var CCM_TOOLS_PATH = \"\u002Findex.php\u002Ftools\u002Frequired\";\n    var CCM_APPLICATION_URL = \"http:\u002F\u002Flocalhost:8888\";\n    var CCM_REL = \"\";\n    var CCM_ACTIVE_LOCALE = \"ja_JP\";\n\u003C\u002Fscript>\n","html",[33,3507,3508,3521,3529,3538,3582,3587,3604,3608,3641,3671,3701,3720,3739,3753,3767,3780,3798,3816,3834,3848,3866],{"__ignoreMap":31},[36,3509,3510,3513,3516,3519],{"class":38,"line":39},[36,3511,3512],{"class":270},"\u003C!",[36,3514,3515],{"class":1278},"DOCTYPE",[36,3517,3518],{"class":355}," html",[36,3520,1282],{"class":270},[36,3522,3523,3525,3527],{"class":38,"line":45},[36,3524,1275],{"class":270},[36,3526,3505],{"class":1278},[36,3528,1282],{"class":270},[36,3530,3531,3533,3536],{"class":38,"line":51},[36,3532,1275],{"class":270},[36,3534,3535],{"class":1278},"head",[36,3537,1282],{"class":270},[36,3539,3540,3542,3545,3548,3550,3552,3555,3557,3559,3561,3563,3566,3568,3570,3572,3574,3577,3579],{"class":38,"line":58},[36,3541,1287],{"class":270},[36,3543,3544],{"class":1278},"link",[36,3546,3547],{"class":355}," rel",[36,3549,317],{"class":270},[36,3551,1298],{"class":270},[36,3553,3554],{"class":274},"stylesheet",[36,3556,1298],{"class":270},[36,3558,1971],{"class":355},[36,3560,317],{"class":270},[36,3562,1298],{"class":270},[36,3564,3565],{"class":274},"text\u002Fcss",[36,3567,1298],{"class":270},[36,3569,1412],{"class":355},[36,3571,317],{"class":270},[36,3573,1298],{"class":270},[36,3575,3576],{"class":274},"\u002Fconcrete\u002Fthemes\u002Fconcrete\u002Fmain.css",[36,3578,1298],{"class":270},[36,3580,3581],{"class":270}," \u002F>\n",[36,3583,3584],{"class":38,"line":64},[36,3585,3586],{"class":263},"    \n",[36,3588,3589,3591,3593,3595,3598,3600,3602],{"class":38,"line":70},[36,3590,1275],{"class":270},[36,3592,1938],{"class":1278},[36,3594,1315],{"class":270},[36,3596,3597],{"class":263},"ログイン :: c5test",[36,3599,1321],{"class":270},[36,3601,1938],{"class":1278},[36,3603,1282],{"class":270},[36,3605,3606],{"class":38,"line":75},[36,3607,55],{"emptyLinePlaceholder":54},[36,3609,3610,3612,3615,3618,3620,3622,3625,3627,3630,3632,3634,3637,3639],{"class":38,"line":81},[36,3611,1275],{"class":270},[36,3613,3614],{"class":1278},"meta",[36,3616,3617],{"class":355}," http-equiv",[36,3619,317],{"class":270},[36,3621,1298],{"class":270},[36,3623,3624],{"class":274},"content-type",[36,3626,1298],{"class":270},[36,3628,3629],{"class":355}," content",[36,3631,317],{"class":270},[36,3633,1298],{"class":270},[36,3635,3636],{"class":274},"text\u002Fhtml; charset=UTF-8",[36,3638,1298],{"class":270},[36,3640,1593],{"class":270},[36,3642,3643,3645,3647,3649,3651,3653,3656,3658,3660,3662,3664,3667,3669],{"class":38,"line":87},[36,3644,1275],{"class":270},[36,3646,3614],{"class":1278},[36,3648,1982],{"class":355},[36,3650,317],{"class":270},[36,3652,1298],{"class":270},[36,3654,3655],{"class":274},"generator",[36,3657,1298],{"class":270},[36,3659,3629],{"class":355},[36,3661,317],{"class":270},[36,3663,1298],{"class":270},[36,3665,3666],{"class":274},"concrete5 - 8.5.4",[36,3668,1298],{"class":270},[36,3670,1593],{"class":270},[36,3672,3673,3675,3677,3679,3681,3683,3686,3688,3690,3692,3694,3697,3699],{"class":38,"line":92},[36,3674,1275],{"class":270},[36,3676,3544],{"class":1278},[36,3678,3547],{"class":355},[36,3680,317],{"class":270},[36,3682,1298],{"class":270},[36,3684,3685],{"class":274},"canonical",[36,3687,1298],{"class":270},[36,3689,1412],{"class":355},[36,3691,317],{"class":270},[36,3693,1298],{"class":270},[36,3695,3696],{"class":274},"http:\u002F\u002Flocalhost:8888\u002Flogin",[36,3698,1298],{"class":270},[36,3700,1282],{"class":270},[36,3702,3703,3705,3707,3709,3711,3713,3716,3718],{"class":38,"line":98},[36,3704,1275],{"class":270},[36,3706,1493],{"class":1278},[36,3708,1971],{"class":355},[36,3710,317],{"class":270},[36,3712,1298],{"class":270},[36,3714,3715],{"class":274},"text\u002Fjavascript",[36,3717,1298],{"class":270},[36,3719,1282],{"class":270},[36,3721,3722,3725,3728,3730,3732,3735,3737],{"class":38,"line":104},[36,3723,3724],{"class":355},"    var",[36,3726,3727],{"class":263}," CCM_DISPATCHER_FILENAME ",[36,3729,317],{"class":270},[36,3731,2880],{"class":270},[36,3733,3734],{"class":274},"\u002Findex.php",[36,3736,1298],{"class":270},[36,3738,1632],{"class":270},[36,3740,3741,3743,3746,3748,3751],{"class":38,"line":481},[36,3742,3724],{"class":355},[36,3744,3745],{"class":263}," CCM_CID ",[36,3747,317],{"class":270},[36,3749,3750],{"class":2763}," 174",[36,3752,1632],{"class":270},[36,3754,3755,3757,3760,3762,3765],{"class":38,"line":487},[36,3756,3724],{"class":355},[36,3758,3759],{"class":263}," CCM_EDIT_MODE ",[36,3761,317],{"class":270},[36,3763,3764],{"class":320}," false",[36,3766,1632],{"class":270},[36,3768,3769,3771,3774,3776,3778],{"class":38,"line":493},[36,3770,3724],{"class":355},[36,3772,3773],{"class":263}," CCM_ARRANGE_MODE ",[36,3775,317],{"class":270},[36,3777,3764],{"class":320},[36,3779,1632],{"class":270},[36,3781,3782,3784,3787,3789,3791,3794,3796],{"class":38,"line":499},[36,3783,3724],{"class":355},[36,3785,3786],{"class":263}," CCM_IMAGE_PATH ",[36,3788,317],{"class":270},[36,3790,2880],{"class":270},[36,3792,3793],{"class":274},"\u002Fconcrete\u002Fimages",[36,3795,1298],{"class":270},[36,3797,1632],{"class":270},[36,3799,3800,3802,3805,3807,3809,3812,3814],{"class":38,"line":505},[36,3801,3724],{"class":355},[36,3803,3804],{"class":263}," CCM_TOOLS_PATH ",[36,3806,317],{"class":270},[36,3808,2880],{"class":270},[36,3810,3811],{"class":274},"\u002Findex.php\u002Ftools\u002Frequired",[36,3813,1298],{"class":270},[36,3815,1632],{"class":270},[36,3817,3818,3820,3823,3825,3827,3830,3832],{"class":38,"line":511},[36,3819,3724],{"class":355},[36,3821,3822],{"class":263}," CCM_APPLICATION_URL ",[36,3824,317],{"class":270},[36,3826,2880],{"class":270},[36,3828,3829],{"class":274},"http:\u002F\u002Flocalhost:8888",[36,3831,1298],{"class":270},[36,3833,1632],{"class":270},[36,3835,3836,3838,3841,3843,3846],{"class":38,"line":517},[36,3837,3724],{"class":355},[36,3839,3840],{"class":263}," CCM_REL ",[36,3842,317],{"class":270},[36,3844,3845],{"class":270}," \"\"",[36,3847,1632],{"class":270},[36,3849,3850,3852,3855,3857,3859,3862,3864],{"class":38,"line":523},[36,3851,3724],{"class":355},[36,3853,3854],{"class":263}," CCM_ACTIVE_LOCALE ",[36,3856,317],{"class":270},[36,3858,2880],{"class":270},[36,3860,3861],{"class":274},"ja_JP",[36,3863,1298],{"class":270},[36,3865,1632],{"class":270},[36,3867,3868,3870,3872],{"class":38,"line":529},[36,3869,1321],{"class":270},[36,3871,1493],{"class":1278},[36,3873,1282],{"class":270},[1290,3875,3877],{"className":3876},[3268,3269],"\n内部の生データが外部からアクセスされるのは非常にまずいのでdashbord配下にルーティングを置き、さらにリクエストの種類をXHRだけにしましょう。\n",[139,3879,3881],{"id":3880},"コンポーネントにajaxアクセスを実装","コンポーネントにAjaxアクセスを実装",[11,3883,3884,3885,3887],{},"URLとデータの取得処理は書いたので、vue側でそこにAjaxを飛ばすようにします。前回作成した",[33,3886,1268],{}," にAjaxの処理を書きます。",[26,3889,3891],{"className":1266,"code":3890,"filename":1268,"language":275,"meta":31,"style":31},"created(){\n    if(this.isEdit){\n        $.ajax({\n            url:location.href,\n            type:'GET',\n            success: (data)=> {\n                let result = JSON.parse(data)[0]; \u002F\u002F returns array\n                this.title = result.title;\n            },\n            error: (xhr, textStatus, errorThrown)=>{\n                console.error('Error! ' + textStatus + ' ' + errorThrown);\n            }\n        })\n    }\n}\n",[33,3892,3893,3898,3903,3908,3913,3918,3923,3928,3933,3938,3943,3948,3952,3957,3961],{"__ignoreMap":31},[36,3894,3895],{"class":38,"line":39},[36,3896,3897],{"class":263},"created(){\n",[36,3899,3900],{"class":38,"line":45},[36,3901,3902],{"class":263},"    if(this.isEdit){\n",[36,3904,3905],{"class":38,"line":51},[36,3906,3907],{"class":263},"        $.ajax({\n",[36,3909,3910],{"class":38,"line":58},[36,3911,3912],{"class":263},"            url:location.href,\n",[36,3914,3915],{"class":38,"line":64},[36,3916,3917],{"class":263},"            type:'GET',\n",[36,3919,3920],{"class":38,"line":70},[36,3921,3922],{"class":263},"            success: (data)=> {\n",[36,3924,3925],{"class":38,"line":75},[36,3926,3927],{"class":263},"                let result = JSON.parse(data)[0]; \u002F\u002F returns array\n",[36,3929,3930],{"class":38,"line":81},[36,3931,3932],{"class":263},"                this.title = result.title;\n",[36,3934,3935],{"class":38,"line":87},[36,3936,3937],{"class":263},"            },\n",[36,3939,3940],{"class":38,"line":92},[36,3941,3942],{"class":263},"            error: (xhr, textStatus, errorThrown)=>{\n",[36,3944,3945],{"class":38,"line":98},[36,3946,3947],{"class":263},"                console.error('Error! ' + textStatus + ' ' + errorThrown);\n",[36,3949,3950],{"class":38,"line":104},[36,3951,2891],{"class":263},[36,3953,3954],{"class":38,"line":481},[36,3955,3956],{"class":263},"        })\n",[36,3958,3959],{"class":38,"line":487},[36,3960,587],{"class":263},[36,3962,3963],{"class":38,"line":493},[36,3964,599],{"class":263},[11,3966,3967,3969,3970,3972],{},[33,3968,1268],{},"は編集と新規追加を併用しているので、",[33,3971,1537],{},"というプロパティでAjaxを飛ばすかを制御しています。現在のURLに対してAjaxを飛ばすと、先ほどのコードで書かれているようにIDに紐づいたアルバム情報をDBから取ってきてくれます。",[11,3974,3975,3976,3979],{},"データはJSONで戻ってくるので　",[33,3977,3978],{},"JSON.prase","を用いてJSで用いられるようにします。もし仮にAjaxが失敗した場合\b（400、500系のエラー）、コンソールでエラーが吐かれるようになっています。",[139,3981,3982],{"id":3982},"編集用コンポーネントのレンダリング設定",[11,3984,3985],{},"シングルページそのものはエントリーポイントだけ。",[26,3987,3990],{"className":28,"code":3988,"filename":3989,"language":30,"meta":31,"style":31},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\n\u003Cdiv id=\"edit\">\u003C\u002Fdiv>\n","edit.php",[33,3991,3992,3996,4000,4004,4008],{"__ignoreMap":31},[36,3993,3994],{"class":38,"line":39},[36,3995,425],{},[36,3997,3998],{"class":38,"line":45},[36,3999,435],{},[36,4001,4002],{"class":38,"line":51},[36,4003,737],{},[36,4005,4006],{"class":38,"line":58},[36,4007,55],{"emptyLinePlaceholder":54},[36,4009,4010],{"class":38,"line":64},[36,4011,4012],{},"\u003Cdiv id=\"edit\">\u003C\u002Fdiv>\n",[11,4014,4015,4016,4019],{},"そしてvue側のeditコンポーネントはpropsを変えるだけで",[33,4017,4018],{},"add.vue","とほぼ同じ",[26,4021,4024],{"className":1266,"code":4022,"filename":4023,"language":275,"meta":31,"style":31},"\u003Ctemplate>\n    \u003CAlbumForm :isEdit=\"true\"\u002F>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport AlbumForm from '.\u002Fcomponents\u002Fform';\nexport default {\n    name:'add',\n    components:{AlbumForm}\n}\n\u003C\u002Fscript>\n","edit.vue",[33,4025,4026,4034,4052,4060,4064,4072,4088,4096,4110,4120,4124],{"__ignoreMap":31},[36,4027,4028,4030,4032],{"class":38,"line":39},[36,4029,1275],{"class":270},[36,4031,1279],{"class":1278},[36,4033,1282],{"class":270},[36,4035,4036,4038,4040,4042,4044,4046,4048,4050],{"class":38,"line":45},[36,4037,1287],{"class":270},[36,4039,1578],{"class":1278},[36,4041,1581],{"class":355},[36,4043,317],{"class":270},[36,4045,1298],{"class":270},[36,4047,751],{"class":274},[36,4049,1298],{"class":270},[36,4051,1593],{"class":270},[36,4053,4054,4056,4058],{"class":38,"line":51},[36,4055,1321],{"class":270},[36,4057,1279],{"class":1278},[36,4059,1282],{"class":270},[36,4061,4062],{"class":38,"line":58},[36,4063,55],{"emptyLinePlaceholder":54},[36,4065,4066,4068,4070],{"class":38,"line":64},[36,4067,1275],{"class":270},[36,4069,1493],{"class":1278},[36,4071,1282],{"class":270},[36,4073,4074,4076,4078,4080,4082,4084,4086],{"class":38,"line":70},[36,4075,260],{"class":259},[36,4077,1620],{"class":263},[36,4079,267],{"class":259},[36,4081,271],{"class":270},[36,4083,1627],{"class":274},[36,4085,382],{"class":270},[36,4087,1632],{"class":270},[36,4089,4090,4092,4094],{"class":38,"line":75},[36,4091,1500],{"class":259},[36,4093,1503],{"class":259},[36,4095,1506],{"class":270},[36,4097,4098,4100,4102,4104,4106,4108],{"class":38,"line":81},[36,4099,1511],{"class":1278},[36,4101,348],{"class":270},[36,4103,382],{"class":270},[36,4105,1651],{"class":274},[36,4107,382],{"class":270},[36,4109,364],{"class":270},[36,4111,4112,4114,4116,4118],{"class":38,"line":87},[36,4113,1660],{"class":1278},[36,4115,1663],{"class":270},[36,4117,1578],{"class":263},[36,4119,599],{"class":270},[36,4121,4122],{"class":38,"line":92},[36,4123,599],{"class":270},[36,4125,4126,4128,4130],{"class":38,"line":98},[36,4127,1321],{"class":270},[36,4129,1493],{"class":1278},[36,4131,1282],{"class":270},[11,4133,4134,4135,4137],{},"最後にレンダー用の",[33,4136,237],{},"を以下のようにしておきます。",[26,4139,4141],{"className":249,"code":4140,"filename":237,"language":252,"meta":31,"style":31},"import Vue from 'vue'\nimport Add from '.\u002Fadd.vue'\nimport Edit from '.\u002Fedit.vue'\n\n\nVue.config.productionTip = false\n\nfunction renderIfidExits(id,vueRoot){\n  if(document.getElementById(id) !== null){\n    return new Vue({\n      render: h => h(vueRoot),\n    }).$mount('#'+id)\n  }\n}\n\nrenderIfidExits('add',Add);\nrenderIfidExits('edit',Edit);\n",[33,4142,4143,4157,4171,4187,4191,4195,4211,4215,4234,4266,4280,4301,4327,4332,4336,4340,4360],{"__ignoreMap":31},[36,4144,4145,4147,4149,4151,4153,4155],{"class":38,"line":39},[36,4146,260],{"class":259},[36,4148,264],{"class":263},[36,4150,267],{"class":259},[36,4152,271],{"class":270},[36,4154,275],{"class":274},[36,4156,278],{"class":270},[36,4158,4159,4161,4163,4165,4167,4169],{"class":38,"line":45},[36,4160,260],{"class":259},[36,4162,1713],{"class":263},[36,4164,267],{"class":259},[36,4166,271],{"class":270},[36,4168,1720],{"class":274},[36,4170,278],{"class":270},[36,4172,4173,4175,4178,4180,4182,4185],{"class":38,"line":51},[36,4174,260],{"class":259},[36,4176,4177],{"class":263}," Edit ",[36,4179,267],{"class":259},[36,4181,271],{"class":270},[36,4183,4184],{"class":274},".\u002Fedit.vue",[36,4186,278],{"class":270},[36,4188,4189],{"class":38,"line":58},[36,4190,55],{"emptyLinePlaceholder":54},[36,4192,4193],{"class":38,"line":64},[36,4194,55],{"emptyLinePlaceholder":54},[36,4196,4197,4199,4201,4203,4205,4207,4209],{"class":38,"line":70},[36,4198,303],{"class":263},[36,4200,306],{"class":270},[36,4202,309],{"class":263},[36,4204,306],{"class":270},[36,4206,314],{"class":263},[36,4208,317],{"class":270},[36,4210,321],{"class":320},[36,4212,4213],{"class":38,"line":75},[36,4214,55],{"emptyLinePlaceholder":54},[36,4216,4217,4220,4223,4225,4227,4229,4232],{"class":38,"line":81},[36,4218,4219],{"class":355},"function",[36,4221,4222],{"class":333}," renderIfidExits",[36,4224,337],{"class":270},[36,4226,757],{"class":351},[36,4228,199],{"class":270},[36,4230,4231],{"class":351},"vueRoot",[36,4233,2740],{"class":270},[36,4235,4236,4239,4241,4244,4246,4249,4251,4253,4256,4259,4262,4264],{"class":38,"line":87},[36,4237,4238],{"class":259},"  if",[36,4240,337],{"class":1278},[36,4242,4243],{"class":263},"document",[36,4245,306],{"class":270},[36,4247,4248],{"class":333},"getElementById",[36,4250,337],{"class":1278},[36,4252,757],{"class":263},[36,4254,4255],{"class":1278},") ",[36,4257,4258],{"class":270},"!==",[36,4260,4261],{"class":270}," null",[36,4263,372],{"class":1278},[36,4265,340],{"class":270},[36,4267,4268,4271,4274,4276,4278],{"class":38,"line":92},[36,4269,4270],{"class":259},"    return",[36,4272,4273],{"class":270}," new",[36,4275,334],{"class":333},[36,4277,337],{"class":1278},[36,4279,340],{"class":270},[36,4281,4282,4285,4287,4289,4291,4293,4295,4297,4299],{"class":38,"line":98},[36,4283,4284],{"class":333},"      render",[36,4286,348],{"class":270},[36,4288,352],{"class":351},[36,4290,356],{"class":355},[36,4292,352],{"class":333},[36,4294,337],{"class":1278},[36,4296,4231],{"class":263},[36,4298,372],{"class":1278},[36,4300,364],{"class":270},[36,4302,4303,4306,4308,4310,4312,4314,4316,4318,4320,4323,4325],{"class":38,"line":104},[36,4304,4305],{"class":270},"    }",[36,4307,372],{"class":1278},[36,4309,306],{"class":270},[36,4311,377],{"class":333},[36,4313,337],{"class":1278},[36,4315,382],{"class":270},[36,4317,1419],{"class":274},[36,4319,382],{"class":270},[36,4321,4322],{"class":270},"+",[36,4324,757],{"class":263},[36,4326,390],{"class":1278},[36,4328,4329],{"class":38,"line":481},[36,4330,4331],{"class":270},"  }\n",[36,4333,4334],{"class":38,"line":487},[36,4335,599],{"class":270},[36,4337,4338],{"class":38,"line":493},[36,4339,55],{"emptyLinePlaceholder":54},[36,4341,4342,4345,4347,4349,4351,4353,4355,4358],{"class":38,"line":499},[36,4343,4344],{"class":333},"renderIfidExits",[36,4346,337],{"class":263},[36,4348,382],{"class":270},[36,4350,1651],{"class":274},[36,4352,382],{"class":270},[36,4354,199],{"class":270},[36,4356,4357],{"class":263},"Add)",[36,4359,1632],{"class":270},[36,4361,4362,4364,4366,4368,4371,4373,4375,4378],{"class":38,"line":505},[36,4363,4344],{"class":333},[36,4365,337],{"class":263},[36,4367,382],{"class":270},[36,4369,4370],{"class":274},"edit",[36,4372,382],{"class":270},[36,4374,199],{"class":270},[36,4376,4377],{"class":263},"Edit)",[36,4379,1632],{"class":270},[11,4381,4382],{},"前回はAddコンポーネントだけでしたが、今回はEditもあります。さらにこのmain.jsで全てのコンポーネントのレンダーを制御しているので、エントリーポイント のIDが存在すればそこにコンポーネントをレンダリングする。という方法を取っています。",[11,4384,4385,4386,4389],{},"本当はコンポーネントごとにレンダー用のjs（",[33,4387,4388],{},"add.js,edit.js","みたいな）を作成するのですが、面倒だったのでこうしました。",[11,4391,4392,4393,4396,4397,4400,4401,4404],{},"そしてform.vueで編集の場合（",[33,4394,4395],{},"isEdit = true","）に",[33,4398,4399],{},"created()","でAjaxを飛ばしてデータを取得し、",[33,4402,4403],{},"data()","に代入するようします。",[18,4406,4407],{"id":4407},"実際にレンダーしてみる",[11,4409,4410,4411,4414],{},"ビルドをして ",[33,4412,4413],{},"\u002Fdashboard\u002Fvuetest\u002Fedit\u002F{id}"," へアクセスします。IDがあっていればそのデータを取ってきてくれます。",[112,4416],{":src":4417,":width":115},"'_mix\u002Fsch-2020-10-04-1.14.27-768x527.png'",[112,4419],{":src":4420,":width":115},"'_mix\u002Fajax-768x764.png'",[11,4422,4423],{},"きちんと画面には前回入力した追加内容が表示されています。開発者ツールでNetworkでAjaxを確認してみましょう。Request Header を確認すると確かに、現在のURLにアクセスしておりさらにXMLHttpRequestで送信されています。Resonseをみてみると",[26,4425,4429],{"className":4426,"code":4427,"language":4428,"meta":31,"style":31},"language-json shiki shiki-themes material-theme-ocean","[\n    {\n        \"id\":\"1\",\n        \"title\":\"\\u30c6\\u30b9\\u30c8\",\n        \"created\":\"2020-08-27 00:28:38\",\n        \"modified\":\"2020-08-27 00:28:38\"\n    }\n]\n","json",[33,4430,4431,4436,4440,4460,4479,4499,4516,4520],{"__ignoreMap":31},[36,4432,4433],{"class":38,"line":39},[36,4434,4435],{"class":270},"[\n",[36,4437,4438],{"class":38,"line":45},[36,4439,484],{"class":270},[36,4441,4442,4445,4447,4449,4451,4453,4456,4458],{"class":38,"line":51},[36,4443,4444],{"class":270},"        \"",[36,4446,757],{"class":355},[36,4448,1298],{"class":270},[36,4450,348],{"class":270},[36,4452,1298],{"class":270},[36,4454,4455],{"class":274},"1",[36,4457,1298],{"class":270},[36,4459,364],{"class":270},[36,4461,4462,4464,4466,4468,4470,4472,4475,4477],{"class":38,"line":58},[36,4463,4444],{"class":270},[36,4465,1938],{"class":355},[36,4467,1298],{"class":270},[36,4469,348],{"class":270},[36,4471,1298],{"class":270},[36,4473,4474],{"class":263},"\\u30c6\\u30b9\\u30c8",[36,4476,1298],{"class":270},[36,4478,364],{"class":270},[36,4480,4481,4483,4486,4488,4490,4492,4495,4497],{"class":38,"line":64},[36,4482,4444],{"class":270},[36,4484,4485],{"class":355},"created",[36,4487,1298],{"class":270},[36,4489,348],{"class":270},[36,4491,1298],{"class":270},[36,4493,4494],{"class":274},"2020-08-27 00:28:38",[36,4496,1298],{"class":270},[36,4498,364],{"class":270},[36,4500,4501,4503,4506,4508,4510,4512,4514],{"class":38,"line":70},[36,4502,4444],{"class":270},[36,4504,4505],{"class":355},"modified",[36,4507,1298],{"class":270},[36,4509,348],{"class":270},[36,4511,1298],{"class":270},[36,4513,4494],{"class":274},[36,4515,2886],{"class":270},[36,4517,4518],{"class":38,"line":75},[36,4519,587],{"class":270},[36,4521,4522],{"class":38,"line":81},[36,4523,1542],{"class":270},[11,4525,4526],{},"このようにデータベースから取ってきた内容がJSONとして渡されているのが確認できます。ちなみに日本語はエンコードされているので、js側でJSON praseを使うことで元の文章に戻すことができます。",[18,4528,4529],{"id":4529},"内容を更新する",[11,4531,4532,4533,4535],{},"編集画面を表示した際の初期表示はできるようになったので、次は内容が書き換えてDBの内容を変更できるようにしましょう。しかし触るのはバックエンドの部分だけです。",[33,4534,3400],{},"を以下のように変更します。",[26,4537,4539],{"className":28,"code":4538,"filename":1102,"language":30,"meta":31,"style":31},"pupublic function edit($id=null){\n\n    \u002F\u002F パラメータがない場合は一覧画面へリダイレクト\n    if($id==null) return Redirect::to('\u002Fdashboard\u002Fvuetest\u002F')->send();\n\n    \u002F\u002F Ajax エンドポイント\n    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $result = $db->fetchAll('SELECT * FROM album ORDER BY ID DESC');\n        $db->Execute(\"COMMIT\");\n        return Core::make('helper\u002Fajax')->sendResult($result);\n    }\n\n    \u002F\u002Fpost処理(ここを追記)\n    if(Request::isPost() == true){\n        $title = $this->post('title');\n\n        if(empty($title)==false){\n            $db = Database::connection();\n            $db->executeQuery(\"START TRANSACTION\");\n            $db->executeQuery(\n                'UPDATE album SET `title`=?, `modified`=now() WHERE `ID`=?',\n                array($title,$id)\n            );\n            $db->executeQuery(\"COMMIT\");\n            Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n        }else{\n            Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n        }\n\n    }else{\n        $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n    }\n}\n",[33,4540,4541,4546,4550,4555,4559,4563,4568,4572,4576,4580,4585,4589,4593,4597,4601,4606,4611,4616,4620,4625,4630,4635,4640,4645,4650,4655,4660,4665,4669,4673,4677,4681,4686,4690,4694],{"__ignoreMap":31},[36,4542,4543],{"class":38,"line":39},[36,4544,4545],{},"pupublic function edit($id=null){\n",[36,4547,4548],{"class":38,"line":45},[36,4549,55],{"emptyLinePlaceholder":54},[36,4551,4552],{"class":38,"line":51},[36,4553,4554],{},"    \u002F\u002F パラメータがない場合は一覧画面へリダイレクト\n",[36,4556,4557],{"class":38,"line":58},[36,4558,3416],{},[36,4560,4561],{"class":38,"line":64},[36,4562,55],{"emptyLinePlaceholder":54},[36,4564,4565],{"class":38,"line":70},[36,4566,4567],{},"    \u002F\u002F Ajax エンドポイント\n",[36,4569,4570],{"class":38,"line":75},[36,4571,3425],{},[36,4573,4574],{"class":38,"line":81},[36,4575,3430],{},[36,4577,4578],{"class":38,"line":87},[36,4579,3435],{},[36,4581,4582],{"class":38,"line":92},[36,4583,4584],{},"        $result = $db->fetchAll('SELECT * FROM album ORDER BY ID DESC');\n",[36,4586,4587],{"class":38,"line":98},[36,4588,3445],{},[36,4590,4591],{"class":38,"line":104},[36,4592,3450],{},[36,4594,4595],{"class":38,"line":481},[36,4596,587],{},[36,4598,4599],{"class":38,"line":487},[36,4600,55],{"emptyLinePlaceholder":54},[36,4602,4603],{"class":38,"line":493},[36,4604,4605],{},"    \u002F\u002Fpost処理(ここを追記)\n",[36,4607,4608],{"class":38,"line":499},[36,4609,4610],{},"    if(Request::isPost() == true){\n",[36,4612,4613],{"class":38,"line":505},[36,4614,4615],{},"        $title = $this->post('title');\n",[36,4617,4618],{"class":38,"line":511},[36,4619,55],{"emptyLinePlaceholder":54},[36,4621,4622],{"class":38,"line":517},[36,4623,4624],{},"        if(empty($title)==false){\n",[36,4626,4627],{"class":38,"line":523},[36,4628,4629],{},"            $db = Database::connection();\n",[36,4631,4632],{"class":38,"line":529},[36,4633,4634],{},"            $db->executeQuery(\"START TRANSACTION\");\n",[36,4636,4637],{"class":38,"line":534},[36,4638,4639],{},"            $db->executeQuery(\n",[36,4641,4642],{"class":38,"line":540},[36,4643,4644],{},"                'UPDATE album SET `title`=?, `modified`=now() WHERE `ID`=?',\n",[36,4646,4647],{"class":38,"line":545},[36,4648,4649],{},"                array($title,$id)\n",[36,4651,4652],{"class":38,"line":550},[36,4653,4654],{},"            );\n",[36,4656,4657],{"class":38,"line":555},[36,4658,4659],{},"            $db->executeQuery(\"COMMIT\");\n",[36,4661,4662],{"class":38,"line":560},[36,4663,4664],{},"            Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n",[36,4666,4667],{"class":38,"line":566},[36,4668,3190],{},[36,4670,4671],{"class":38,"line":572},[36,4672,4664],{},[36,4674,4675],{"class":38,"line":578},[36,4676,2251],{},[36,4678,4679],{"class":38,"line":584},[36,4680,55],{"emptyLinePlaceholder":54},[36,4682,4683],{"class":38,"line":590},[36,4684,4685],{},"    }else{\n",[36,4687,4688],{"class":38,"line":596},[36,4689,1173],{},[36,4691,4692],{"class":38,"line":1017},[36,4693,587],{},[36,4695,4696],{"class":38,"line":1023},[36,4697,599],{},[11,4699,4700,4701,4704],{},"新規作成の際に使用される",[33,4702,4703],{},"pupublic function edit"," を一部変更したぐらいです。postがある場合、その値のバリデーションをして変更するIDを元に更新用のSQLを走らせるだけです。",[139,4706,4707],{"id":4707},"実際に変更してみる",[112,4709],{":src":4710,":width":115},"'_mix\u002Fsch-2020-10-04-13.37.28-768x396.png'",[112,4712],{":src":4713,":width":115},"'_mix\u002Fsch-2020-10-04-13.38.13.png'",[11,4715,4716],{},"無事、タイトルと編集時間が更新されました。これでCRUDの「Update」が完成しました。",[18,4718,4719],{"id":4719},"一覧画面を作成する",[11,4721,4722],{},"追加・編集の画面は完成しました。次は全ての登録データを一覧で見れる画面を作成していきます。\u002Fdashboard\u002Fvuetest\u002F にアクセスした際に一覧が表示されるようにします。",[139,4724,4725],{"id":4725},"一覧用コンポーネントの作成",[11,4727,4728],{},"一覧コンポーネントをindex.vueとしておきます。一覧画面では以下のような構成にしています。",[26,4730,4733],{"className":1266,"code":4731,"filename":4732,"language":275,"meta":31,"style":31},"\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Ch3>アルバム一覧\u003C\u002Fh3>\n        \u003Chr>\n\n        \u003Ctable class=\"p-package-index table table-hover\">\n            \u003Cthead>\n                \u003Ctr>\n                    \u003Cth class=\"c-dol-title\">タイトル\u003C\u002Fth>\n                    \u003Cth class=\"c-dol-publish-date\">作成日\u003C\u002Fth>\n                    \u003Cth class=\"c-dol-operation\">操作\u003C\u002Fth>\n                \u003C\u002Ftr>\n            \u003C\u002Fthead>\n            \u003Ctbody>\n                \u003Ctr v-for=\"val in list\" :key=\"val.id\" tabindex=\"0\">\n                    \u003Ctd style=\"vertical-align:middle;\">{{val.title}}\u003C\u002Ftd>\n                    \u003Ctd style=\"vertical-align:middle;\">{{val.created}}\u003C\u002Ftd>\n                    \u003Ctd style=\"vertical-align:middle;\">\n                        \u003Ca :href=\"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id\" type=\"button\" class=\"btn btn-success btn-sm\" style=\"margin-right:10px;\">編集\u003C\u002Fa>\n                        \u003Cbutton type=\"button\" class=\"btn btn-danger btn-sm\" v-on:click=\"cofirmDelete(val)\">削除\u003C\u002Fbutton>\n                    \u003C\u002Ftd>\n                \u003C\u002Ftr>\n            \u003C\u002Ftbody>\n        \u003C\u002Ftable>\n\n        \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n            \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                \u003Ca href=\"\u002Fdashboard\u002Fvuetest\u002Fadd\" class=\"pull-right btn btn-primary\">\n                    新規追加\n                \u003C\u002Fa>\n            \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n    name:'index',\n    data(){\n        return {\n            list:[],\n            isProcessing:false\n        }\n    },\n    methods:{\n        cofirmDelete(obj){\n            let result = window.confirm('アルバム：「'+obj.title+'」を本当に削除しますか？この操作は取り消せません。');\n            if(result) return this.deleteAlubm(obj.id);\n        },\n        deleteAlubm(id){\n            if(this.isProcessing==false){\n                this.isProcessing = true;\n\n                $.ajax({\n                    url:'\u002Fdashboard\u002Fvuetest\u002FdeleteData\u002F',\n                    type:'POST',\n                    data:{target:id},\n                    success: ()=> {\n                        let targetIndex = this.list.findIndex((ele)=>{\n                            return ele.ID == id;\n                        });\n                        this.list.splice(targetIndex,1);\n                        this.isProcessing = false;\n                    },\n                    error: (xhr, textStatus, errorThrown)=>{\n                        console.log('Error! ' + textStatus + ' ' + errorThrown);\n                    }\n                })\n            }\n        },\n    },\n    created(){\n        $.ajax({\n            url:'\u002Fdashboard\u002Fvuetest\u002FloadData',\n            type:'GET',\n            success: (data)=> {\n                this.list = JSON.parse(data); \u002F\u002F returns array\n            },\n            error: (xhr, textStatus, errorThrown)=>{\n                console.error('Error! ' + textStatus + ' ' + errorThrown);\n            }\n        })\n    }\n}\n\u003C\u002Fscript>\n","index.vue",[33,4734,4735,4743,4761,4778,4786,4790,4810,4819,4828,4857,4885,4913,4921,4929,4938,4981,5011,5038,5056,5118,5168,5176,5184,5192,5200,5204,5222,5240,5268,5273,5281,5289,5297,5305,5313,5317,5325,5333,5348,5354,5360,5372,5382,5386,5390,5396,5408,5456,5489,5495,5507,5528,5541,5546,5561,5578,5595,5613,5629,5663,5685,5695,5721,5734,5740,5770,5809,5815,5822,5827,5832,5837,5845,5859,5875,5892,5911,5941,5946,5972,6008,6013,6021,6026,6031],{"__ignoreMap":31},[36,4736,4737,4739,4741],{"class":38,"line":39},[36,4738,1275],{"class":270},[36,4740,1279],{"class":1278},[36,4742,1282],{"class":270},[36,4744,4745,4747,4749,4751,4753,4755,4757,4759],{"class":38,"line":45},[36,4746,1287],{"class":270},[36,4748,1290],{"class":1278},[36,4750,1293],{"class":355},[36,4752,317],{"class":270},[36,4754,1298],{"class":270},[36,4756,1301],{"class":274},[36,4758,1298],{"class":270},[36,4760,1282],{"class":270},[36,4762,4763,4765,4767,4769,4772,4774,4776],{"class":38,"line":51},[36,4764,1310],{"class":270},[36,4766,139],{"class":1278},[36,4768,1315],{"class":270},[36,4770,4771],{"class":263},"アルバム一覧",[36,4773,1321],{"class":270},[36,4775,139],{"class":1278},[36,4777,1282],{"class":270},[36,4779,4780,4782,4784],{"class":38,"line":58},[36,4781,1310],{"class":270},[36,4783,1898],{"class":1278},[36,4785,1282],{"class":270},[36,4787,4788],{"class":38,"line":64},[36,4789,55],{"emptyLinePlaceholder":54},[36,4791,4792,4794,4797,4799,4801,4803,4806,4808],{"class":38,"line":70},[36,4793,1310],{"class":270},[36,4795,4796],{"class":1278},"table",[36,4798,1293],{"class":355},[36,4800,317],{"class":270},[36,4802,1298],{"class":270},[36,4804,4805],{"class":274},"p-package-index table table-hover",[36,4807,1298],{"class":270},[36,4809,1282],{"class":270},[36,4811,4812,4814,4817],{"class":38,"line":75},[36,4813,1353],{"class":270},[36,4815,4816],{"class":1278},"thead",[36,4818,1282],{"class":270},[36,4820,4821,4823,4826],{"class":38,"line":81},[36,4822,1373],{"class":270},[36,4824,4825],{"class":1278},"tr",[36,4827,1282],{"class":270},[36,4829,4830,4832,4835,4837,4839,4841,4844,4846,4848,4851,4853,4855],{"class":38,"line":87},[36,4831,2059],{"class":270},[36,4833,4834],{"class":1278},"th",[36,4836,1293],{"class":355},[36,4838,317],{"class":270},[36,4840,1298],{"class":270},[36,4842,4843],{"class":274},"c-dol-title",[36,4845,1298],{"class":270},[36,4847,1315],{"class":270},[36,4849,4850],{"class":263},"タイトル",[36,4852,1321],{"class":270},[36,4854,4834],{"class":1278},[36,4856,1282],{"class":270},[36,4858,4859,4861,4863,4865,4867,4869,4872,4874,4876,4879,4881,4883],{"class":38,"line":92},[36,4860,2059],{"class":270},[36,4862,4834],{"class":1278},[36,4864,1293],{"class":355},[36,4866,317],{"class":270},[36,4868,1298],{"class":270},[36,4870,4871],{"class":274},"c-dol-publish-date",[36,4873,1298],{"class":270},[36,4875,1315],{"class":270},[36,4877,4878],{"class":263},"作成日",[36,4880,1321],{"class":270},[36,4882,4834],{"class":1278},[36,4884,1282],{"class":270},[36,4886,4887,4889,4891,4893,4895,4897,4900,4902,4904,4907,4909,4911],{"class":38,"line":98},[36,4888,2059],{"class":270},[36,4890,4834],{"class":1278},[36,4892,1293],{"class":355},[36,4894,317],{"class":270},[36,4896,1298],{"class":270},[36,4898,4899],{"class":274},"c-dol-operation",[36,4901,1298],{"class":270},[36,4903,1315],{"class":270},[36,4905,4906],{"class":263},"操作",[36,4908,1321],{"class":270},[36,4910,4834],{"class":1278},[36,4912,1282],{"class":270},[36,4914,4915,4917,4919],{"class":38,"line":104},[36,4916,1399],{"class":270},[36,4918,4825],{"class":1278},[36,4920,1282],{"class":270},[36,4922,4923,4925,4927],{"class":38,"line":481},[36,4924,1452],{"class":270},[36,4926,4816],{"class":1278},[36,4928,1282],{"class":270},[36,4930,4931,4933,4936],{"class":38,"line":487},[36,4932,1353],{"class":270},[36,4934,4935],{"class":1278},"tbody",[36,4937,1282],{"class":270},[36,4939,4940,4942,4944,4947,4949,4951,4954,4956,4959,4961,4963,4966,4968,4971,4973,4975,4977,4979],{"class":38,"line":493},[36,4941,1373],{"class":270},[36,4943,4825],{"class":1278},[36,4945,4946],{"class":355}," v-for",[36,4948,317],{"class":270},[36,4950,1298],{"class":270},[36,4952,4953],{"class":274},"val in list",[36,4955,1298],{"class":270},[36,4957,4958],{"class":355}," :key",[36,4960,317],{"class":270},[36,4962,1298],{"class":270},[36,4964,4965],{"class":274},"val.id",[36,4967,1298],{"class":270},[36,4969,4970],{"class":355}," tabindex",[36,4972,317],{"class":270},[36,4974,1298],{"class":270},[36,4976,2764],{"class":274},[36,4978,1298],{"class":270},[36,4980,1282],{"class":270},[36,4982,4983,4985,4988,4991,4993,4995,4998,5000,5002,5005,5007,5009],{"class":38,"line":499},[36,4984,2059],{"class":270},[36,4986,4987],{"class":1278},"td",[36,4989,4990],{"class":355}," style",[36,4992,317],{"class":270},[36,4994,1298],{"class":270},[36,4996,4997],{"class":274},"vertical-align:middle;",[36,4999,1298],{"class":270},[36,5001,1315],{"class":270},[36,5003,5004],{"class":263},"{{val.title}}",[36,5006,1321],{"class":270},[36,5008,4987],{"class":1278},[36,5010,1282],{"class":270},[36,5012,5013,5015,5017,5019,5021,5023,5025,5027,5029,5032,5034,5036],{"class":38,"line":505},[36,5014,2059],{"class":270},[36,5016,4987],{"class":1278},[36,5018,4990],{"class":355},[36,5020,317],{"class":270},[36,5022,1298],{"class":270},[36,5024,4997],{"class":274},[36,5026,1298],{"class":270},[36,5028,1315],{"class":270},[36,5030,5031],{"class":263},"{{val.created}}",[36,5033,1321],{"class":270},[36,5035,4987],{"class":1278},[36,5037,1282],{"class":270},[36,5039,5040,5042,5044,5046,5048,5050,5052,5054],{"class":38,"line":511},[36,5041,2059],{"class":270},[36,5043,4987],{"class":1278},[36,5045,4990],{"class":355},[36,5047,317],{"class":270},[36,5049,1298],{"class":270},[36,5051,4997],{"class":274},[36,5053,1298],{"class":270},[36,5055,1282],{"class":270},[36,5057,5058,5061,5063,5066,5068,5070,5073,5075,5077,5079,5081,5083,5085,5087,5089,5091,5094,5096,5098,5100,5102,5105,5107,5109,5112,5114,5116],{"class":38,"line":517},[36,5059,5060],{"class":270},"                        \u003C",[36,5062,807],{"class":1278},[36,5064,5065],{"class":355}," :href",[36,5067,317],{"class":270},[36,5069,1298],{"class":270},[36,5071,5072],{"class":274},"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id",[36,5074,1298],{"class":270},[36,5076,1971],{"class":355},[36,5078,317],{"class":270},[36,5080,1298],{"class":270},[36,5082,1376],{"class":274},[36,5084,1298],{"class":270},[36,5086,1293],{"class":355},[36,5088,317],{"class":270},[36,5090,1298],{"class":270},[36,5092,5093],{"class":274},"btn btn-success btn-sm",[36,5095,1298],{"class":270},[36,5097,4990],{"class":355},[36,5099,317],{"class":270},[36,5101,1298],{"class":270},[36,5103,5104],{"class":274},"margin-right:10px;",[36,5106,1298],{"class":270},[36,5108,1315],{"class":270},[36,5110,5111],{"class":263},"編集",[36,5113,1321],{"class":270},[36,5115,807],{"class":1278},[36,5117,1282],{"class":270},[36,5119,5120,5122,5124,5126,5128,5130,5132,5134,5136,5138,5140,5143,5145,5148,5150,5152,5155,5157,5159,5162,5164,5166],{"class":38,"line":523},[36,5121,5060],{"class":270},[36,5123,1376],{"class":1278},[36,5125,1971],{"class":355},[36,5127,317],{"class":270},[36,5129,1298],{"class":270},[36,5131,1376],{"class":274},[36,5133,1298],{"class":270},[36,5135,1293],{"class":355},[36,5137,317],{"class":270},[36,5139,1298],{"class":270},[36,5141,5142],{"class":274},"btn btn-danger btn-sm",[36,5144,1298],{"class":270},[36,5146,5147],{"class":355}," v-on:click",[36,5149,317],{"class":270},[36,5151,1298],{"class":270},[36,5153,5154],{"class":274},"cofirmDelete(val)",[36,5156,1298],{"class":270},[36,5158,1315],{"class":270},[36,5160,5161],{"class":263},"削除",[36,5163,1321],{"class":270},[36,5165,1376],{"class":1278},[36,5167,1282],{"class":270},[36,5169,5170,5172,5174],{"class":38,"line":529},[36,5171,2083],{"class":270},[36,5173,4987],{"class":1278},[36,5175,1282],{"class":270},[36,5177,5178,5180,5182],{"class":38,"line":534},[36,5179,1399],{"class":270},[36,5181,4825],{"class":1278},[36,5183,1282],{"class":270},[36,5185,5186,5188,5190],{"class":38,"line":540},[36,5187,1452],{"class":270},[36,5189,4935],{"class":1278},[36,5191,1282],{"class":270},[36,5193,5194,5196,5198],{"class":38,"line":545},[36,5195,1461],{"class":270},[36,5197,4796],{"class":1278},[36,5199,1282],{"class":270},[36,5201,5202],{"class":38,"line":550},[36,5203,55],{"emptyLinePlaceholder":54},[36,5205,5206,5208,5210,5212,5214,5216,5218,5220],{"class":38,"line":555},[36,5207,1310],{"class":270},[36,5209,1290],{"class":1278},[36,5211,1293],{"class":355},[36,5213,317],{"class":270},[36,5215,1298],{"class":270},[36,5217,1344],{"class":274},[36,5219,1298],{"class":270},[36,5221,1282],{"class":270},[36,5223,5224,5226,5228,5230,5232,5234,5236,5238],{"class":38,"line":560},[36,5225,1353],{"class":270},[36,5227,1290],{"class":1278},[36,5229,1293],{"class":355},[36,5231,317],{"class":270},[36,5233,1298],{"class":270},[36,5235,1364],{"class":274},[36,5237,1298],{"class":270},[36,5239,1282],{"class":270},[36,5241,5242,5244,5246,5248,5250,5252,5254,5256,5258,5260,5262,5264,5266],{"class":38,"line":566},[36,5243,1373],{"class":270},[36,5245,807],{"class":1278},[36,5247,1412],{"class":355},[36,5249,317],{"class":270},[36,5251,1298],{"class":270},[36,5253,1800],{"class":274},[36,5255,1298],{"class":270},[36,5257,1293],{"class":355},[36,5259,317],{"class":270},[36,5261,1298],{"class":270},[36,5263,1430],{"class":274},[36,5265,1298],{"class":270},[36,5267,1282],{"class":270},[36,5269,5270],{"class":38,"line":572},[36,5271,5272],{"class":263},"                    新規追加\n",[36,5274,5275,5277,5279],{"class":38,"line":578},[36,5276,1399],{"class":270},[36,5278,807],{"class":1278},[36,5280,1282],{"class":270},[36,5282,5283,5285,5287],{"class":38,"line":584},[36,5284,1452],{"class":270},[36,5286,1290],{"class":1278},[36,5288,1282],{"class":270},[36,5290,5291,5293,5295],{"class":38,"line":590},[36,5292,1461],{"class":270},[36,5294,1290],{"class":1278},[36,5296,1282],{"class":270},[36,5298,5299,5301,5303],{"class":38,"line":596},[36,5300,1470],{"class":270},[36,5302,1290],{"class":1278},[36,5304,1282],{"class":270},[36,5306,5307,5309,5311],{"class":38,"line":1017},[36,5308,1321],{"class":270},[36,5310,1279],{"class":1278},[36,5312,1282],{"class":270},[36,5314,5315],{"class":38,"line":1023},[36,5316,55],{"emptyLinePlaceholder":54},[36,5318,5319,5321,5323],{"class":38,"line":1028},[36,5320,1275],{"class":270},[36,5322,1493],{"class":1278},[36,5324,1282],{"class":270},[36,5326,5327,5329,5331],{"class":38,"line":1033},[36,5328,1500],{"class":259},[36,5330,1503],{"class":259},[36,5332,1506],{"class":270},[36,5334,5335,5337,5339,5341,5344,5346],{"class":38,"line":1038},[36,5336,1511],{"class":1278},[36,5338,348],{"class":270},[36,5340,382],{"class":270},[36,5342,5343],{"class":274},"index",[36,5345,382],{"class":270},[36,5347,364],{"class":270},[36,5349,5350,5352],{"class":38,"line":1043},[36,5351,2226],{"class":1278},[36,5353,2229],{"class":270},[36,5355,5356,5358],{"class":38,"line":1048},[36,5357,2234],{"class":259},[36,5359,1506],{"class":270},[36,5361,5362,5365,5367,5370],{"class":38,"line":1053},[36,5363,5364],{"class":1278},"            list",[36,5366,348],{"class":270},[36,5368,5369],{"class":1278},"[]",[36,5371,364],{"class":270},[36,5373,5374,5377,5379],{"class":38,"line":1058},[36,5375,5376],{"class":1278},"            isProcessing",[36,5378,348],{"class":270},[36,5380,5381],{"class":320},"false\n",[36,5383,5384],{"class":38,"line":1063},[36,5385,2251],{"class":270},[36,5387,5388],{"class":38,"line":1068},[36,5389,2719],{"class":270},[36,5391,5392,5394],{"class":38,"line":1073},[36,5393,2724],{"class":1278},[36,5395,2727],{"class":270},[36,5397,5398,5401,5403,5406],{"class":38,"line":2902},[36,5399,5400],{"class":1278},"        cofirmDelete",[36,5402,337],{"class":270},[36,5404,5405],{"class":351},"obj",[36,5407,2740],{"class":270},[36,5409,5410,5413,5416,5418,5421,5423,5426,5428,5430,5433,5435,5437,5439,5441,5443,5445,5447,5450,5452,5454],{"class":38,"line":2907},[36,5411,5412],{"class":355},"            let",[36,5414,5415],{"class":263}," result",[36,5417,2877],{"class":270},[36,5419,5420],{"class":263}," window",[36,5422,306],{"class":270},[36,5424,5425],{"class":333},"confirm",[36,5427,337],{"class":1278},[36,5429,382],{"class":270},[36,5431,5432],{"class":274},"アルバム：「",[36,5434,382],{"class":270},[36,5436,4322],{"class":270},[36,5438,5405],{"class":263},[36,5440,306],{"class":270},[36,5442,1938],{"class":263},[36,5444,4322],{"class":270},[36,5446,382],{"class":270},[36,5448,5449],{"class":274},"」を本当に削除しますか？この操作は取り消せません。",[36,5451,382],{"class":270},[36,5453,372],{"class":1278},[36,5455,1632],{"class":270},[36,5457,5459,5461,5463,5466,5468,5471,5474,5477,5479,5481,5483,5485,5487],{"class":38,"line":5458},48,[36,5460,2745],{"class":259},[36,5462,337],{"class":1278},[36,5464,5465],{"class":263},"result",[36,5467,4255],{"class":1278},[36,5469,5470],{"class":259},"return",[36,5472,5473],{"class":270}," this.",[36,5475,5476],{"class":333},"deleteAlubm",[36,5478,337],{"class":1278},[36,5480,5405],{"class":263},[36,5482,306],{"class":270},[36,5484,757],{"class":263},[36,5486,372],{"class":1278},[36,5488,1632],{"class":270},[36,5490,5492],{"class":38,"line":5491},49,[36,5493,5494],{"class":270},"        },\n",[36,5496,5498,5501,5503,5505],{"class":38,"line":5497},50,[36,5499,5500],{"class":1278},"        deleteAlubm",[36,5502,337],{"class":270},[36,5504,757],{"class":351},[36,5506,2740],{"class":270},[36,5508,5510,5512,5514,5516,5519,5522,5524,5526],{"class":38,"line":5509},51,[36,5511,2745],{"class":259},[36,5513,337],{"class":1278},[36,5515,2750],{"class":270},[36,5517,5518],{"class":263},"isProcessing",[36,5520,5521],{"class":270},"==",[36,5523,1588],{"class":320},[36,5525,372],{"class":1278},[36,5527,340],{"class":270},[36,5529,5531,5533,5535,5537,5539],{"class":38,"line":5530},52,[36,5532,2871],{"class":270},[36,5534,5518],{"class":263},[36,5536,2877],{"class":270},[36,5538,2776],{"class":320},[36,5540,1632],{"class":270},[36,5542,5544],{"class":38,"line":5543},53,[36,5545,55],{"emptyLinePlaceholder":54},[36,5547,5549,5552,5554,5557,5559],{"class":38,"line":5548},54,[36,5550,5551],{"class":263},"                $",[36,5553,306],{"class":270},[36,5555,5556],{"class":333},"ajax",[36,5558,337],{"class":1278},[36,5560,340],{"class":270},[36,5562,5564,5567,5569,5571,5574,5576],{"class":38,"line":5563},55,[36,5565,5566],{"class":1278},"                    url",[36,5568,348],{"class":270},[36,5570,382],{"class":270},[36,5572,5573],{"class":274},"\u002Fdashboard\u002Fvuetest\u002FdeleteData\u002F",[36,5575,382],{"class":270},[36,5577,364],{"class":270},[36,5579,5581,5584,5586,5588,5591,5593],{"class":38,"line":5580},56,[36,5582,5583],{"class":1278},"                    type",[36,5585,348],{"class":270},[36,5587,382],{"class":270},[36,5589,5590],{"class":274},"POST",[36,5592,382],{"class":270},[36,5594,364],{"class":270},[36,5596,5598,5601,5603,5606,5608,5610],{"class":38,"line":5597},57,[36,5599,5600],{"class":1278},"                    data",[36,5602,1663],{"class":270},[36,5604,5605],{"class":1278},"target",[36,5607,348],{"class":270},[36,5609,757],{"class":263},[36,5611,5612],{"class":270},"},\n",[36,5614,5616,5619,5621,5624,5627],{"class":38,"line":5615},58,[36,5617,5618],{"class":333},"                    success",[36,5620,348],{"class":270},[36,5622,5623],{"class":270}," ()",[36,5625,5626],{"class":355},"=>",[36,5628,1506],{"class":270},[36,5630,5632,5635,5638,5640,5642,5645,5647,5650,5652,5654,5657,5659,5661],{"class":38,"line":5631},59,[36,5633,5634],{"class":355},"                        let",[36,5636,5637],{"class":263}," targetIndex",[36,5639,2877],{"class":270},[36,5641,5473],{"class":270},[36,5643,5644],{"class":263},"list",[36,5646,306],{"class":270},[36,5648,5649],{"class":333},"findIndex",[36,5651,337],{"class":1278},[36,5653,337],{"class":270},[36,5655,5656],{"class":351},"ele",[36,5658,372],{"class":270},[36,5660,5626],{"class":355},[36,5662,340],{"class":270},[36,5664,5666,5669,5672,5674,5677,5680,5683],{"class":38,"line":5665},60,[36,5667,5668],{"class":259},"                            return",[36,5670,5671],{"class":263}," ele",[36,5673,306],{"class":270},[36,5675,5676],{"class":263},"ID",[36,5678,5679],{"class":270}," ==",[36,5681,5682],{"class":263}," id",[36,5684,1632],{"class":270},[36,5686,5688,5691,5693],{"class":38,"line":5687},61,[36,5689,5690],{"class":270},"                        }",[36,5692,372],{"class":1278},[36,5694,1632],{"class":270},[36,5696,5698,5701,5703,5705,5708,5710,5713,5715,5717,5719],{"class":38,"line":5697},62,[36,5699,5700],{"class":270},"                        this.",[36,5702,5644],{"class":263},[36,5704,306],{"class":270},[36,5706,5707],{"class":333},"splice",[36,5709,337],{"class":1278},[36,5711,5712],{"class":263},"targetIndex",[36,5714,199],{"class":270},[36,5716,4455],{"class":2763},[36,5718,372],{"class":1278},[36,5720,1632],{"class":270},[36,5722,5724,5726,5728,5730,5732],{"class":38,"line":5723},63,[36,5725,5700],{"class":270},[36,5727,5518],{"class":263},[36,5729,2877],{"class":270},[36,5731,3764],{"class":320},[36,5733,1632],{"class":270},[36,5735,5737],{"class":38,"line":5736},64,[36,5738,5739],{"class":270},"                    },\n",[36,5741,5743,5746,5748,5751,5754,5756,5759,5761,5764,5766,5768],{"class":38,"line":5742},65,[36,5744,5745],{"class":333},"                    error",[36,5747,348],{"class":270},[36,5749,5750],{"class":270}," (",[36,5752,5753],{"class":351},"xhr",[36,5755,199],{"class":270},[36,5757,5758],{"class":351}," textStatus",[36,5760,199],{"class":270},[36,5762,5763],{"class":351}," errorThrown",[36,5765,372],{"class":270},[36,5767,5626],{"class":355},[36,5769,340],{"class":270},[36,5771,5773,5776,5778,5781,5783,5785,5788,5790,5793,5795,5797,5799,5801,5803,5805,5807],{"class":38,"line":5772},66,[36,5774,5775],{"class":263},"                        console",[36,5777,306],{"class":270},[36,5779,5780],{"class":333},"log",[36,5782,337],{"class":1278},[36,5784,382],{"class":270},[36,5786,5787],{"class":274},"Error! ",[36,5789,382],{"class":270},[36,5791,5792],{"class":270}," +",[36,5794,5758],{"class":263},[36,5796,5792],{"class":270},[36,5798,271],{"class":270},[36,5800,271],{"class":270},[36,5802,5792],{"class":270},[36,5804,5763],{"class":263},[36,5806,372],{"class":1278},[36,5808,1632],{"class":270},[36,5810,5812],{"class":38,"line":5811},67,[36,5813,5814],{"class":270},"                    }\n",[36,5816,5818,5820],{"class":38,"line":5817},68,[36,5819,2864],{"class":270},[36,5821,390],{"class":1278},[36,5823,5825],{"class":38,"line":5824},69,[36,5826,2891],{"class":270},[36,5828,5830],{"class":38,"line":5829},70,[36,5831,5494],{"class":270},[36,5833,5835],{"class":38,"line":5834},71,[36,5836,2719],{"class":270},[36,5838,5840,5843],{"class":38,"line":5839},72,[36,5841,5842],{"class":1278},"    created",[36,5844,2229],{"class":270},[36,5846,5848,5851,5853,5855,5857],{"class":38,"line":5847},73,[36,5849,5850],{"class":263},"        $",[36,5852,306],{"class":270},[36,5854,5556],{"class":333},[36,5856,337],{"class":1278},[36,5858,340],{"class":270},[36,5860,5862,5865,5867,5869,5871,5873],{"class":38,"line":5861},74,[36,5863,5864],{"class":1278},"            url",[36,5866,348],{"class":270},[36,5868,382],{"class":270},[36,5870,3491],{"class":274},[36,5872,382],{"class":270},[36,5874,364],{"class":270},[36,5876,5878,5881,5883,5885,5888,5890],{"class":38,"line":5877},75,[36,5879,5880],{"class":1278},"            type",[36,5882,348],{"class":270},[36,5884,382],{"class":270},[36,5886,5887],{"class":274},"GET",[36,5889,382],{"class":270},[36,5891,364],{"class":270},[36,5893,5895,5898,5900,5902,5905,5907,5909],{"class":38,"line":5894},76,[36,5896,5897],{"class":333},"            success",[36,5899,348],{"class":270},[36,5901,5750],{"class":270},[36,5903,5904],{"class":351},"data",[36,5906,372],{"class":270},[36,5908,5626],{"class":355},[36,5910,1506],{"class":270},[36,5912,5914,5916,5918,5920,5923,5925,5928,5930,5932,5934,5937],{"class":38,"line":5913},77,[36,5915,2871],{"class":270},[36,5917,5644],{"class":263},[36,5919,2877],{"class":270},[36,5921,5922],{"class":263}," JSON",[36,5924,306],{"class":270},[36,5926,5927],{"class":333},"parse",[36,5929,337],{"class":1278},[36,5931,5904],{"class":263},[36,5933,372],{"class":1278},[36,5935,5936],{"class":270},";",[36,5938,5940],{"class":5939},"sC9rS"," \u002F\u002F returns array\n",[36,5942,5944],{"class":38,"line":5943},78,[36,5945,3937],{"class":270},[36,5947,5949,5952,5954,5956,5958,5960,5962,5964,5966,5968,5970],{"class":38,"line":5948},79,[36,5950,5951],{"class":333},"            error",[36,5953,348],{"class":270},[36,5955,5750],{"class":270},[36,5957,5753],{"class":351},[36,5959,199],{"class":270},[36,5961,5758],{"class":351},[36,5963,199],{"class":270},[36,5965,5763],{"class":351},[36,5967,372],{"class":270},[36,5969,5626],{"class":355},[36,5971,340],{"class":270},[36,5973,5975,5978,5980,5982,5984,5986,5988,5990,5992,5994,5996,5998,6000,6002,6004,6006],{"class":38,"line":5974},80,[36,5976,5977],{"class":263},"                console",[36,5979,306],{"class":270},[36,5981,2813],{"class":333},[36,5983,337],{"class":1278},[36,5985,382],{"class":270},[36,5987,5787],{"class":274},[36,5989,382],{"class":270},[36,5991,5792],{"class":270},[36,5993,5758],{"class":263},[36,5995,5792],{"class":270},[36,5997,271],{"class":270},[36,5999,271],{"class":270},[36,6001,5792],{"class":270},[36,6003,5763],{"class":263},[36,6005,372],{"class":1278},[36,6007,1632],{"class":270},[36,6009,6011],{"class":38,"line":6010},81,[36,6012,2891],{"class":270},[36,6014,6016,6019],{"class":38,"line":6015},82,[36,6017,6018],{"class":270},"        }",[36,6020,390],{"class":1278},[36,6022,6024],{"class":38,"line":6023},83,[36,6025,587],{"class":270},[36,6027,6029],{"class":38,"line":6028},84,[36,6030,599],{"class":270},[36,6032,6034,6036,6038],{"class":38,"line":6033},85,[36,6035,1321],{"class":270},[36,6037,1493],{"class":1278},[36,6039,1282],{"class":270},[11,6041,6042],{},"レンダリングされる際は以下のような処理で一覧画面が表示されます。",[6044,6045,6046,6049,6052],"ol",{},[126,6047,6048],{},"createdでDB上の情報を取ってくるAjaxをエンドポイントに飛ばす。",[126,6050,6051],{},"取得したデータをdata()のlistに挿入。",[126,6053,6054],{},"v-forでlist分 の行を表示する。",[11,6056,6057],{},"これをレンダーすると以下のようになります。",[112,6059],{":src":6060,":width":115},"'_mix\u002Fsch-2020-10-04-14.40.28-768x285.png'",[11,6062,6063],{},"右側の「操作」で、「編集」でそのアルバムデータの編集画面へ移動、「削除」ではそのデータを削除するAjaxを飛ばします。また、「新規追加」では新規追加画面へ移動します。この画面があれば一通りのデータ操作がブラウザ画面からできるようになります。",[139,6065,6067],{"id":6066},"ロード用削除用エンドポイントを作成","ロード用・削除用エンドポイントを作成",[11,6069,6070,6072],{},[33,6071,3400],{}," コントローラーでは一覧データ・対象のIDを削除するAjaxエンドポイントを作成します。",[26,6074,6076],{"className":28,"code":6075,"filename":1102,"language":30,"meta":31,"style":31},"public function view() {\n    $this->render('\u002Fdashboard\u002Fvuetest\u002Fview');\n}\n\n\u002F\u002F ロード用のエンドポイント\npublic function loadData() {\n    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $result = $db->fetchAll('SELECT * FROM album ORDER BY ID DESC');\n        $db->Execute(\"COMMIT\");\n        return Core::make('helper\u002Fajax')->sendResult($result);\n    }else{\n        $this->replace('\u002Fpage_not_found');\n    }\n}\n\n\u002F\u002F 削除エンドポイント\npublic function deleteData(){\n    $targetID=$this->post('target');\n    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' && !is_null($targetID)){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $db->executeQuery('DELETE FROM album WHERE `ID`=?',array($targetID));\n        $db->Execute(\"COMMIT\");\n    }else{\n        $this->replace('\u002Fpage_not_found');\n    }\n}\n",[33,6077,6078,6083,6088,6092,6096,6101,6106,6111,6115,6119,6123,6127,6131,6135,6140,6144,6148,6152,6157,6162,6167,6172,6176,6180,6185,6189,6193,6197,6201],{"__ignoreMap":31},[36,6079,6080],{"class":38,"line":39},[36,6081,6082],{},"public function view() {\n",[36,6084,6085],{"class":38,"line":45},[36,6086,6087],{},"    $this->render('\u002Fdashboard\u002Fvuetest\u002Fview');\n",[36,6089,6090],{"class":38,"line":51},[36,6091,599],{},[36,6093,6094],{"class":38,"line":58},[36,6095,55],{"emptyLinePlaceholder":54},[36,6097,6098],{"class":38,"line":64},[36,6099,6100],{},"\u002F\u002F ロード用のエンドポイント\n",[36,6102,6103],{"class":38,"line":70},[36,6104,6105],{},"public function loadData() {\n",[36,6107,6108],{"class":38,"line":75},[36,6109,6110],{},"    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n",[36,6112,6113],{"class":38,"line":81},[36,6114,3430],{},[36,6116,6117],{"class":38,"line":87},[36,6118,3435],{},[36,6120,6121],{"class":38,"line":92},[36,6122,4584],{},[36,6124,6125],{"class":38,"line":98},[36,6126,3445],{},[36,6128,6129],{"class":38,"line":104},[36,6130,3450],{},[36,6132,6133],{"class":38,"line":481},[36,6134,4685],{},[36,6136,6137],{"class":38,"line":487},[36,6138,6139],{},"        $this->replace('\u002Fpage_not_found');\n",[36,6141,6142],{"class":38,"line":493},[36,6143,587],{},[36,6145,6146],{"class":38,"line":499},[36,6147,599],{},[36,6149,6150],{"class":38,"line":505},[36,6151,55],{"emptyLinePlaceholder":54},[36,6153,6154],{"class":38,"line":511},[36,6155,6156],{},"\u002F\u002F 削除エンドポイント\n",[36,6158,6159],{"class":38,"line":517},[36,6160,6161],{},"public function deleteData(){\n",[36,6163,6164],{"class":38,"line":523},[36,6165,6166],{},"    $targetID=$this->post('target');\n",[36,6168,6169],{"class":38,"line":529},[36,6170,6171],{},"    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' && !is_null($targetID)){\n",[36,6173,6174],{"class":38,"line":534},[36,6175,3430],{},[36,6177,6178],{"class":38,"line":540},[36,6179,3435],{},[36,6181,6182],{"class":38,"line":545},[36,6183,6184],{},"        $db->executeQuery('DELETE FROM album WHERE `ID`=?',array($targetID));\n",[36,6186,6187],{"class":38,"line":550},[36,6188,3445],{},[36,6190,6191],{"class":38,"line":555},[36,6192,4685],{},[36,6194,6195],{"class":38,"line":560},[36,6196,6139],{},[36,6198,6199],{"class":38,"line":566},[36,6200,587],{},[36,6202,6203],{"class":38,"line":572},[36,6204,599],{},[139,6206,6208],{"id":6207},"エントリーポイント-を作成","エントリーポイント を作成",[11,6210,6211],{},"上記のコンポーネントをレンダリングするために編集・追加の時のように、一覧用ページにレンダーできるように設定をします。",[11,6213,6214,6217],{},[33,6215,6216],{},"packages\u002Fvuetest\u002Fsingle_pages\u002Fdashboard\u002Fvuetest\u002Fview.php"," に以下のようにエントリーポイントを記述します。",[26,6219,6221],{"className":28,"code":6220,"filename":722,"language":30,"meta":31,"style":31},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\n\u003Cdiv id=\"index\">\u003C\u002Fdiv>\n",[33,6222,6223,6227,6231,6235,6239],{"__ignoreMap":31},[36,6224,6225],{"class":38,"line":39},[36,6226,425],{},[36,6228,6229],{"class":38,"line":45},[36,6230,435],{},[36,6232,6233],{"class":38,"line":51},[36,6234,737],{},[36,6236,6237],{"class":38,"line":58},[36,6238,55],{"emptyLinePlaceholder":54},[36,6240,6241],{"class":38,"line":64},[36,6242,6243],{},"\u003Cdiv id=\"index\">\u003C\u002Fdiv>\n",[11,6245,6246],{},"そしてmain.jsでは",[26,6248,6250],{"className":249,"code":6249,"filename":237,"language":252,"meta":31,"style":31},"import Vue from 'vue'\nimport Index from '.\u002Findex.vue'\nimport Add from '.\u002Fadd.vue'\nimport Edit from '.\u002Fedit.vue'\n\n\nVue.config.productionTip = false\n\nfunction renderIfidExits(id,vueRoot){\n  if(document.getElementById(id) !== null){\n    return new Vue({\n      render: h => h(vueRoot),\n    }).$mount('#'+id)\n  }\n}\n\nrenderIfidExits('index',Index);\nrenderIfidExits('add',Add);\nrenderIfidExits('edit',Edit);\n",[33,6251,6252,6266,6282,6296,6310,6314,6318,6334,6338,6354,6380,6392,6412,6436,6440,6444,6448,6467,6485],{"__ignoreMap":31},[36,6253,6254,6256,6258,6260,6262,6264],{"class":38,"line":39},[36,6255,260],{"class":259},[36,6257,264],{"class":263},[36,6259,267],{"class":259},[36,6261,271],{"class":270},[36,6263,275],{"class":274},[36,6265,278],{"class":270},[36,6267,6268,6270,6273,6275,6277,6280],{"class":38,"line":45},[36,6269,260],{"class":259},[36,6271,6272],{"class":263}," Index ",[36,6274,267],{"class":259},[36,6276,271],{"class":270},[36,6278,6279],{"class":274},".\u002Findex.vue",[36,6281,278],{"class":270},[36,6283,6284,6286,6288,6290,6292,6294],{"class":38,"line":51},[36,6285,260],{"class":259},[36,6287,1713],{"class":263},[36,6289,267],{"class":259},[36,6291,271],{"class":270},[36,6293,1720],{"class":274},[36,6295,278],{"class":270},[36,6297,6298,6300,6302,6304,6306,6308],{"class":38,"line":58},[36,6299,260],{"class":259},[36,6301,4177],{"class":263},[36,6303,267],{"class":259},[36,6305,271],{"class":270},[36,6307,4184],{"class":274},[36,6309,278],{"class":270},[36,6311,6312],{"class":38,"line":64},[36,6313,55],{"emptyLinePlaceholder":54},[36,6315,6316],{"class":38,"line":70},[36,6317,55],{"emptyLinePlaceholder":54},[36,6319,6320,6322,6324,6326,6328,6330,6332],{"class":38,"line":75},[36,6321,303],{"class":263},[36,6323,306],{"class":270},[36,6325,309],{"class":263},[36,6327,306],{"class":270},[36,6329,314],{"class":263},[36,6331,317],{"class":270},[36,6333,321],{"class":320},[36,6335,6336],{"class":38,"line":81},[36,6337,55],{"emptyLinePlaceholder":54},[36,6339,6340,6342,6344,6346,6348,6350,6352],{"class":38,"line":87},[36,6341,4219],{"class":355},[36,6343,4222],{"class":333},[36,6345,337],{"class":270},[36,6347,757],{"class":351},[36,6349,199],{"class":270},[36,6351,4231],{"class":351},[36,6353,2740],{"class":270},[36,6355,6356,6358,6360,6362,6364,6366,6368,6370,6372,6374,6376,6378],{"class":38,"line":92},[36,6357,4238],{"class":259},[36,6359,337],{"class":1278},[36,6361,4243],{"class":263},[36,6363,306],{"class":270},[36,6365,4248],{"class":333},[36,6367,337],{"class":1278},[36,6369,757],{"class":263},[36,6371,4255],{"class":1278},[36,6373,4258],{"class":270},[36,6375,4261],{"class":270},[36,6377,372],{"class":1278},[36,6379,340],{"class":270},[36,6381,6382,6384,6386,6388,6390],{"class":38,"line":98},[36,6383,4270],{"class":259},[36,6385,4273],{"class":270},[36,6387,334],{"class":333},[36,6389,337],{"class":1278},[36,6391,340],{"class":270},[36,6393,6394,6396,6398,6400,6402,6404,6406,6408,6410],{"class":38,"line":104},[36,6395,4284],{"class":333},[36,6397,348],{"class":270},[36,6399,352],{"class":351},[36,6401,356],{"class":355},[36,6403,352],{"class":333},[36,6405,337],{"class":1278},[36,6407,4231],{"class":263},[36,6409,372],{"class":1278},[36,6411,364],{"class":270},[36,6413,6414,6416,6418,6420,6422,6424,6426,6428,6430,6432,6434],{"class":38,"line":481},[36,6415,4305],{"class":270},[36,6417,372],{"class":1278},[36,6419,306],{"class":270},[36,6421,377],{"class":333},[36,6423,337],{"class":1278},[36,6425,382],{"class":270},[36,6427,1419],{"class":274},[36,6429,382],{"class":270},[36,6431,4322],{"class":270},[36,6433,757],{"class":263},[36,6435,390],{"class":1278},[36,6437,6438],{"class":38,"line":487},[36,6439,4331],{"class":270},[36,6441,6442],{"class":38,"line":493},[36,6443,599],{"class":270},[36,6445,6446],{"class":38,"line":499},[36,6447,55],{"emptyLinePlaceholder":54},[36,6449,6450,6452,6454,6456,6458,6460,6462,6465],{"class":38,"line":505},[36,6451,4344],{"class":333},[36,6453,337],{"class":263},[36,6455,382],{"class":270},[36,6457,5343],{"class":274},[36,6459,382],{"class":270},[36,6461,199],{"class":270},[36,6463,6464],{"class":263},"Index)",[36,6466,1632],{"class":270},[36,6468,6469,6471,6473,6475,6477,6479,6481,6483],{"class":38,"line":511},[36,6470,4344],{"class":333},[36,6472,337],{"class":263},[36,6474,382],{"class":270},[36,6476,1651],{"class":274},[36,6478,382],{"class":270},[36,6480,199],{"class":270},[36,6482,4357],{"class":263},[36,6484,1632],{"class":270},[36,6486,6487,6489,6491,6493,6495,6497,6499,6501],{"class":38,"line":517},[36,6488,4344],{"class":333},[36,6490,337],{"class":263},[36,6492,382],{"class":270},[36,6494,4370],{"class":274},[36,6496,382],{"class":270},[36,6498,199],{"class":270},[36,6500,4377],{"class":263},[36,6502,1632],{"class":270},[11,6504,6505,6508],{},[33,6506,6507],{},"id='index'","があれば一覧のコンポーネントが出力されるようにしました。",[18,6510,6511],{"id":6511},"実際に操作してみる",[139,6513,6514],{"id":6514},"新しくデータを入れてみる",[112,6516],{":src":6517,":width":115},"'_mix\u002Fsch-2020-10-04-14.40.28-768x285-2.png'",[11,6519,6520],{},"右下の「新規追加」は \u002Fdashboard\u002Fvuetest\u002Fadd へリンクしています。そのためクリックすると追加画面が現れて、追加ができます。新規に「テスト２」としておきましょう。",[112,6522],{":src":6523,":width":115},"'_mix\u002Fsch-2020-10-04-15.11.23-768x216.png'",[11,6525,6526],{},"それで「登録」を押すとデータ挿入処理と共に一覧へリダイレクトされます。すると、",[112,6528],{":src":6529,":width":115},"'_mix\u002Fsch-2020-10-04-15.12.17-768x313.png'",[11,6531,6532],{},"きちんと一覧に反映されました。",[18,6534,6535],{"id":6535},"削除してみる",[11,6537,6538],{},"では削除を押すと、確認ダイアログがでてOKであれば削除APIが走って実行されます。",[112,6540],{":src":6541,":width":750,":center":751},"'_mix\u002Fsch-2020-10-04-15.13.59-768x251.png'",[112,6543],{":src":6544,":width":115},"'_mix\u002Fsch-2020-10-04-15.22.02.png'",[11,6546,6547],{},"「変更テスト（id 1）」がDB上から削除されまた、一覧からも消えました。",[139,6549,6550],{"id":6550},"編集してみる",[11,6552,6553],{},"緑色の「編集」は編集画面のURLへリンクしています。vueでは以下のようにv-for内で動的に作成できるようにしています。",[26,6555,6557],{"className":1266,"code":6556,"language":275,"meta":4732,"style":31},"\u003Ctr v-for=\"val in list\" :key=\"val.id\" tabindex=\"0\">\n...\n    \u003Ctd style=\"vertical-align:middle;\">\n        ...\n        \u003Ca target=\"_blank\" :href=\"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id\">編集\u003C\u002Fa>\n        ...\n    \u003C\u002Ftd>\n...\n\u003C\u002Ftr>\n",[33,6558,6559,6613,6617,6622,6627,6632,6636,6641,6645],{"__ignoreMap":31},[36,6560,6561,6563,6565,6567,6569,6571,6574,6577,6580,6582,6585,6588,6590,6592,6595,6597,6599,6601,6603,6605,6607,6609,6611],{"class":38,"line":39},[36,6562,1275],{"class":270},[36,6564,4825],{"class":1278},[36,6566,4946],{"class":259},[36,6568,317],{"class":270},[36,6570,1298],{"class":270},[36,6572,6573],{"class":263},"val ",[36,6575,6576],{"class":270},"in",[36,6578,6579],{"class":263}," list",[36,6581,1298],{"class":270},[36,6583,6584],{"class":270}," :",[36,6586,6587],{"class":355},"key",[36,6589,317],{"class":270},[36,6591,1298],{"class":270},[36,6593,6594],{"class":263},"val",[36,6596,306],{"class":270},[36,6598,757],{"class":263},[36,6600,1298],{"class":270},[36,6602,4970],{"class":355},[36,6604,317],{"class":270},[36,6606,1298],{"class":270},[36,6608,2764],{"class":274},[36,6610,1298],{"class":270},[36,6612,1282],{"class":270},[36,6614,6615],{"class":38,"line":45},[36,6616,593],{"class":263},[36,6618,6619],{"class":38,"line":51},[36,6620,6621],{"class":263},"    \u003Ctd style=\"vertical-align:middle;\">\n",[36,6623,6624],{"class":38,"line":58},[36,6625,6626],{"class":263},"        ...\n",[36,6628,6629],{"class":38,"line":64},[36,6630,6631],{"class":263},"        \u003Ca target=\"_blank\" :href=\"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id\">編集\u003C\u002Fa>\n",[36,6633,6634],{"class":38,"line":70},[36,6635,6626],{"class":263},[36,6637,6638],{"class":38,"line":75},[36,6639,6640],{"class":263},"    \u003C\u002Ftd>\n",[36,6642,6643],{"class":38,"line":81},[36,6644,593],{"class":263},[36,6646,6647,6649,6651],{"class":38,"line":87},[36,6648,1321],{"class":270},[36,6650,4825],{"class":1278},[36,6652,1282],{"class":270},[11,6654,6655],{},"実際にリンクしてみると、選択したデータの編集画面が表示されました。",[112,6657],{":src":6658,":width":750,":center":751},"'_mix\u002Fsch-2020-10-04-15.29.21-768x342.png'",[18,6660,6661],{"id":3304},"次回は..",[11,6663,6664],{},"今回の記事では編集画面と一覧画面が完成しました。これで「作成」「読み取り」「更新」「削除」の実装ができました。次の記事では「タイトル」だけでなく「画像データ」「リッチテキスト」といったデータを使えるようにします。",[766,6666,6667],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":31,"searchDepth":51,"depth":51,"links":6669},[6670,6675,6676,6679,6684,6687,6690],{"id":3371,"depth":45,"text":3372,"children":6671},[6672,6673,6674],{"id":3385,"depth":51,"text":3386},{"id":3880,"depth":51,"text":3881},{"id":3982,"depth":51,"text":3982},{"id":4407,"depth":45,"text":4407},{"id":4529,"depth":45,"text":4529,"children":6677},[6678],{"id":4707,"depth":51,"text":4707},{"id":4719,"depth":45,"text":4719,"children":6680},[6681,6682,6683],{"id":4725,"depth":51,"text":4725},{"id":6066,"depth":51,"text":6067},{"id":6207,"depth":51,"text":6208},{"id":6511,"depth":45,"text":6511,"children":6685},[6686],{"id":6514,"depth":51,"text":6514},{"id":6535,"depth":45,"text":6535,"children":6688},[6689],{"id":6550,"depth":51,"text":6550},{"id":3304,"depth":45,"text":6661},[783],"2020-10-04","oncrete5にVueCLIを使ってUIを構築する。編集画面と一覧画面。",{},"\u002Fseries\u002Fconcrete5vue-3",{"title":3357,"description":6693},"series\u002Fconcrete5vue-3",[793,794,275],"b60sq7M9Lg8p5F-WfOF_VM7wNdrKWtYXHxXbLU-P1O4",1780987151695]