Это будет пересмотр структуры формы NewCafe.vue. Давайте сделаем шаг назад и подумаем, чего мы пытаемся достичь.

У нас есть кафе. В этих кафе много детей и, возможно, один родитель. Каждое кафе, будь то родительское или дочернее, имеет несколько типов пива. Каждое кафе имеет уникальный идентификатор, родительский или дочерний, который является строкой в ​​нашей таблице cafes.

Разница между родительским и дочерним кафе:
1. Адрес
2. Название местоположения (уникальное для местоположения)
3. Методы приготовления

Я думаю, что мы должны сделать в форме кнопку, которая добавляет новое местоположение для каждого поля, уникального для этого местоположения. Это потребует реструктуризации данных, отправляемых на сервер. Я бы сказал, что, поскольку мы все еще находимся в бета-версии и у нас нет сторонних приложений, интегрирующихся с вашим API, нам пока не нужно делать /v2 API. Тем не менее, это будет одна из ситуаций, когда вы определенно захотите изменить версию маршрута после того, как откроете его публично.

Шаг 2: Знайте, что нам нужно настроить

Таким образом, мы не только настраиваем отображение формы, группируя уникальные данные и позволяя пользователю редактировать по желанию. Мы также корректируем методы модуля Vuex и вызовы API. В учебнике по отношениям многие ко многим https://serversideup.net/many-many-relationships-laravel/ я заявил, что мы настроили модули Vuex так, чтобы они были готовы хранить данные для методов варки. Я следовал схеме здесь для создания учебника Vuex: Сборка модуля Vuex — серверная сторона вверх

Помимо формы, нам придется настроить:
* Диспетчер для сохранения кафе
* API Javascript для отправки кафе на сервер
* Обновить проверки на стороне сервера, чтобы принять новая структура

Шаг 3: Начните изменять NewCafe.vue

Первое, что мы хотим сделать, это удалить старые поля адреса из метода data() и добавить массив locations: []. Мы также хотим удалить старые поля адреса из validations и добавить массив locations: [] и проверку oneLocation, которые я объясню по ходу дела. Наш новый метод data() должен выглядеть так:

data(){
  return {
    name: '',
    locations: [],
    website: '',
    description: '',
    roaster: false,
    validations: {
      name: {
        is_valid: true,
        text: ''
      },
      locations: [],
      oneLocation: {
        is_valid: true,
        text: ''
      },
      website: {
        is_valid: true,
        text: ''
      }
    }
  }
},

Массив местоположений будет содержать все отдельные данные для каждого местоположения по мере его добавления. Массив местоположений валидации будет содержать валидации для каждого местоположения по мере его добавления. Это гарантирует, что у нас нет добавленного местоположения с неверными данными. Проверка oneLocation гарантирует, что в кафе добавлено хотя бы одно место.

Далее мы добавим к нашим методам метод с именем addLocation() и вызовем его при создании компонента. Метод должен выглядеть так:

addLocation(){
  this.locations.push( { name: '', address: '', city: '', state: '', zip: '', methodsAvailable: [] } );
  this.validations.locations.push({
    address: {
      is_valid: true,
      text: ''
    },
    city: {
      is_valid: true,
      text: ''
    },
    state: {
      is_valid: true,
      text: ''
    },
    zip: {
      is_valid: true,
      text: ''
    }
  });
},

Что это делает, так это помещает объект местоположения в наш массив местоположения в данных с полями для имени, адреса, города, штата, почтового индекса и другим массивом для доступных методов, которые будут методами заваривания. Мы действительно собираемся использовать некоторую больную реактивность VueJS. Следующая часть метода подталкивает проверки для каждого из новых полей, которые мы вводим. Мы не указали имена и доступные методы по следующей причине. Во-первых, если имя оставить пустым, мы будем использовать поле имени из кафе, которое все еще присутствует, это поле не требуется. Во-вторых, при добавлении кафе вы можете не знать всех способов приготовления. Это тоже нормально, они не должны требоваться. Когда мы сделаем еще несколько руководств по API и поработаем с методом PUT, мы напишем обновляемые маршруты для кафе.

Теперь, когда компонент создан, вызовите метод, чтобы добавить местоположение следующим образом:

created(){
  this.addLocation();
},

Это инициализирует наше первое местоположение.

Шаг 5: Добавьте шаблон для заполнения формы

Это огромный шаг в изменении данных. Нам нужен визуальный дисплей для ввода полей. Во-первых, я попрошу вас удалить существующие поля, которые мы переместили в такие местоположения, как адрес, город, штат и почтовый индекс. Затем я попрошу вас добавить этот фрагмент кода:

<div class="grid-container">
  <div class="grid-x grid-padding-x" v-for="(location, key) in locations">
    <div class="large-12 medium-12 small-12 cell">
      <h3>Location</h3>
    </div>
    <div class="large-6 medium-6 small-12 cell">
      <label>Location Name
        <input type="text" placeholder="Location Name" v-model="locations[key].name">
      </label>
    </div>
    <div class="large-6 medium-6 small-12 cell">
      <label>Address
        <input type="text" placeholder="Address" v-model="locations[key].address">
      </label>
      <span class="validation" v-show="!validations.locations[key].address.is_valid">{{ validations.locations[key].address.text }}</span>
    </div>
    <div class="large-6 medium-6 small-12 cell">
      <label>City
        <input type="text" placeholder="City" v-model="locations[key].city">
      </label>
      <span class="validation" v-show="!validations.locations[key].city.is_valid">{{ validations.locations[key].city.text }}</span>
    </div>
    <div class="large-6 medium-6 small-12 cell">
      <label>State
        <input type="text" placeholder="State" v-model="locations[key].state">
      </label>
      <span class="validation" v-show="!validations.locations[key].state.is_valid">{{ validations.locations[key].state.text }}</span>
    </div>
    <div class="large-6 medium-6 small-12 cell">
      <label>Zip
        <input type="text" placeholder="Zip" v-model="locations[key].zip">
      </label>
      <span class="validation" v-show="!validations.locations[key].zip.is_valid">{{ validations.locations[key].zip.text }}</span>
    </div>
    <div class="large-12 medium-12 small-12 cell">
      <label>Brew Methods Available</label>
      <span class="brew-method" v-for="brewMethod in brewMethods">
        <input v-bind:id="'brew-method-'+brewMethod.id+'-'+key" type="checkbox" v-bind:value="brewMethod.id" v-model="locations[key].methodsAvailable"><label v-bind:for="'brew-method-'+brewMethod.id+'-'+key">{{ brewMethod.method }}</label>
      </span>
    </div>
    <div class="large-12 medium-12 small-12 cell">
      <a class="button" v-on:click="removeLocation( key )">Remove Location</a>
    </div>
  </div>
</div>

Определенно придется что-то объяснять! Итак, мы убрали существующую информацию о кафе с одним местоположением из формы и добавили динамически создаваемую форму, в которой вы можете добавить столько мест в кафе, сколько хотите, и удалить те, которые были добавлены случайно.

Во-первых, сразу проверьте эту строку:

<div class="grid-x grid-padding-x" v-for="(location, key) in locations">

Это делает цикл по всем местоположениям в массиве местоположений и захвату местоположения и ключа. Помните, что на последнем шаге это генерируется динамически, поэтому каждый раз, когда вы добавляете местоположение, VueJS использует свои реактивные мощности для добавления поля для редактирования данных.

Мы также будем использовать ключ, чтобы установить модель на каждом из входов формы. Давайте посмотрим на поле «Название местоположения»:

<label>Location Name
  <input type="text" placeholder="Location Name" v-model="locations[key].name">
</label>

См. ссылки на модель locations[key].name, это ссылка на объект местоположения в определенном ключе и имя, связанное с ним. Вся остальная логика, связанная с полями местоположения, такая же. Теперь мы можем проверить это отдельное поле, и у нас есть модель VueJS для его отображения.

Давайте проверим следующий элемент проверки:

<span class="validation" v-show="!validations.locations[key].address.is_valid">{{ validations.locations[key].address.text }}</span>

Это подтверждает адрес по ключу. Теперь мы можем специально отображать проверку для динамически добавляемого поля формы в VueJS.

Следующий фрагмент кода для изучения:

<span class="brew-method" v-for="brewMethod in brewMethods">
        <input v-bind:id="'brew-method-'+brewMethod.id+'-'+key" type="checkbox" v-bind:value="brewMethod.id" v-model="locations[key].methodsAvailable"><label v-bind:for="'brew-method-'+brewMethod.id+'-'+key">{{ brewMethod.method }}</label>

Что здесь происходит, так это то, что нам нужен набор методов заваривания, доступных в определенном месте. У нас есть v-model ссылка на местоположение по ключу, к которому мы добавляем методы заваривания, но есть одна вещь, на которую следует обратить внимание, это id. У меня есть ключ, представляющий собой комбинацию, если идентификатор метода заваривания и ключ местоположения, чтобы убедиться, они уникальны.

Наконец, проверьте метод удаления:

<div class="large-12 medium-12 small-12 cell">
  <a class="button" v-on:click="removeLocation( key )">Remove Location</a>
</div>

Если вы случайно добавите слишком много местоположений, было бы неплохо иметь возможность удалить одно из них. Это вызывает метод с именем removeLocation и передает ключ местоположения. Метод объединяет массив местоположения по ключу, поэтому он полностью удаляется. Вы должны добавить метод к вашему объекту methods следующим образом:

removeLocation( key ){
  this.locations.splice( key, 1 );
  this.validations.locations.splice( key, 1 );
}

Он не только удаляет местоположение, но также удаляет проверку местоположения.

Шаг 6. Включите методы заваривания в форму

Поскольку мы повторяем методы варки, было бы неплохо взять их из хранилища данных. Мы уже загрузили их в наш Layout.vue при загрузке страницы, поэтому они уже доступны. Все, что нам нужно сделать сейчас, это добавить его к нашим вычисляемым переменным следующим образом:

computed: {
  brewMethods(){
    return this.$store.getters.getBrewMethods;
  }
},

Теперь у нас есть методы заваривания, доступные в нашей форме.

Шаг 7: Проверка динамической формы

Самая сложная часть проверки динамической формы — неизвестно, сколько данных нам нужно проверить. Это происходит потому, что мы можем разрешить кафе неограниченное количество мест. К счастью, мы уже подготовили нашу форму для обработки этих изменений с помощью массива местоположений и массива местоположений для проверки.

После того как вы удалили отдельные проверки для адреса, города, штата и почтового индекса, добавьте следующий код:

/*
  Ensure all locations entered are valid
*/
for( var index in this.locations ) {
   if (this.locations.hasOwnProperty( index ) ) {
     /*
       Ensure an address has been entered
     */
     if( this.locations[index].address.trim() == '' ){
       validNewCafeForm = false;
       this.validations.locations[index].address.is_valid = false;
       this.validations.locations[index].address.text = 'Please enter an address for the new cafe!';
     }else{
       this.validations.locations[index].address.is_valid = true;
       this.validations.locations[index].address.text = '';
     }
   }

   /*
     Ensure a city has been entered
   */
   if( this.locations[index].city.trim() == '' ){
     validNewCafeForm = false;
     this.validations.locations[index].city.is_valid = false;
     this.validations.locations[index].city.text = 'Please enter a city for the new cafe!';
   }else{
     this.validations.locations[index].city.is_valid = true;
     this.validations.locations[index].city.text = '';
   }

   /*
     Ensure a state has been entered
   */
   if( this.locations[index].state.trim() == '' ){
     validNewCafeForm = false;
     this.validations.locations[index].state.is_valid = false;
     this.validations.locations[index].state.text = 'Please enter a state for the new cafe!';
   }else{
     this.validations.locations[index].state.is_valid = true;
     this.validations.locations[index].state.text = '';
   }

   /*
     Ensure a zip has been entered
   */
   if( this.locations[index].zip.trim() == '' || !this.locations[index].zip.match(/(^\d{5}$)/) ){
     validNewCafeForm = false;
     this.validations.locations[index].zip.is_valid = false;
     this.validations.locations[index].zip.text = 'Please enter a valid zip code for the new cafe!';
   }else{
     this.validations.locations[index].zip.is_valid = true;
     this.validations.locations[index].zip.text = '';
   }
}

What this does is iterate over all of the locations data and validates each piece. We iterate over it as an object in case the keys are out of order if we remove a location. Now each of the validations is keyed to the specific field in the array along with the text.

If you look at one of the lines, like:

this.validations.locations[index].zip.is_valid = false;
this.validations.locations[index].zip.text = 'Please enter a valid zip code for the new cafe!';

вы увидите, что если одно из полей недействительно, оно имеет соответствующий ключ. Вот как мы ориентируемся на динамические поля.

Еще одно быстрое обновление проверки: мы добавили проверку URL-адреса для поля веб-сайта, которое является дополнительным полем, которое мы добавили:

/*
  If a website has been entered, ensure the URL is valid
*/
if( this.website.trim != '' && !this.website.match(/^((https?):\/\/)?([w|W]{3}\.)+[a-zA-Z0-9\-\.]{3,}\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/) ){
  validNewCafeForm = false;
  this.validations.website.is_valid = false;
  this.validations.website.text = 'Please enter a valid URL for the website!';
}else{
  this.validations.website.is_valid = true;
  this.validations.website.text = '';
}

Это просто проверяет, есть ли у нас веб-сайт и является ли он действительным URL-адресом. Остальные проверки остаются прежними, как и весь процесс. Мы вернем false, если форма недействительна.

Шаг 8: Обновление addCafe Dispatch

Теперь, когда у нас есть действующая форма с целой кучей новых полей, нам нужно правильно передать их действию, чтобы мы могли сохранить новое кафе.

В нашем методе submitNewCafe() мы добавим дополнительные поля и реструктурируем наши адреса, чтобы они находились в местоположениях. Наши обновления должны выглядеть так:

submitNewCafe(){
  if( this.validateNewCafe() ){
    this.$store.dispatch( 'addCafe', {
      name: this.name,
      locations: this.locations,
      website: this.website,
      description: this.description,
      roaster: this.roaster
    });
  }
},

Теперь мы передаем все данные о местоположении в виде массива, а веб-сайт, описание и параметры ростера мы добавили позже. Помните, что наши методы заваривания теперь специфичны для каждого кафе.

Шаг 9: Обновление API cafe.js

После обновления диспетчера addCafe нам нужно настроить метод действия обработчика в модуле resources/assets/js/modules/cafes.js Vuex. Прямо сейчас этот метод принимает объект данных, но передает старую структуру в API.

Во-первых, нам нужно обновить это, чтобы передать новую структуру следующим образом:

addCafe( { commit, state, dispatch }, data ){
  commit( 'setCafeAddedStatus', 1 );

  CafeAPI.postAddNewCafe( data.name, data.locations, data.website, data.description, data.roaster )
      .then( function( response ){
        commit( 'setCafeAddedStatus', 2 );
        dispatch( 'loadCafes' );
      })
      .catch( function(){
        commit( 'setCafeAddedStatus', 3 );
      });
}

Это передает обновленные данные в API.

Теперь нам нужно открыть наш файл /resources/assets/js/cafe.js и настроить API для отправки новых данных на сервер.

Вызывается метод postAddNewCafe(), и нам нужно обновить параметры и полезную нагрузку метода следующим образом:

/*
  POST  /api/v1/cafes
*/
postAddNewCafe: function( name, locations, website, description, roaster ){
  return axios.post( ROAST_CONFIG.API_URL + '/cafes',
    {
      name: name,
      locations: locations,
      website: website,
      description: description,
      roaster: roaster
    }
  );
}

Теперь мы передаем данные в правильном формате со стороны JS на сервер, чтобы они соответствовали тому, что у нас сейчас есть в нашей динамической форме. Теперь нам нужно просто обновить проверку на стороне сервера, чтобы убедиться, что мы получаем достоверные данные.

Шаг 10: Обновление проверки на стороне сервера

Прямо сейчас, если бы мы отправили нашу форму, мы бы получили массу проблем с проверкой, потому что наш запрос проверяется в формате старых данных. Нам нужно убедиться, что новые данные проверены.

Сначала мы открываем наш файл /app/Http/Requests/StoreCafeRequest.php.

В массиве проверки удалите старые данные адреса:

return [
    'name'         => 'required',
    'website'      => 'sometimes|url'
];

Все это объединено в локации. Нам также необходимо удалить старые адресные данные из массива сообщений.

Теперь нам нужно добавить проверки для массива местоположений. В Laravel есть несколько встроенных правил проверки для массивов, перечисленных здесь: Проверка — Laravel — PHP Framework для веб-мастеров.

Что вы можете сделать, так это использовать * для любого ключа, а затем проверить каждую часть массива. Проверка нашего массива местоположений должна выглядеть так:

'name'                    => 'required',
'location.*.address'      => 'required',
'location.*.city'         => 'required',
'location.*.state'        => 'required',
'location.*.zip'          => 'required|regex:/\b\d{5}\b/',
'location.*.brew_methods' => 'sometimes|array',
'website'                 => 'sometimes|url'

Теперь любой ключ в нашем массиве местоположений будет проверяться в соответствии с правилами. Довольно болен, а?

Шаг 11: Сохранение нового запроса формы

Теперь, когда у нас есть действительные данные, поступающие в нашу конечную точку API, пришло время добавить данные в базу данных.

Нам нужно будет открыть наш файл /app/Http/Controllers/API/CafesController.php и внести некоторые изменения в метод postNewCafe.

Поскольку мы добавили несколько локаций и возможность для родительского кафе (по сути, используемого для группировки кафе), нам нужно внести много изменений.

Сначала давайте добавим весь наш код и разберем его:

$addedCafes = array();

$locations = $request->get('locations');

/*
  Create a parent cafe and grab the first location
*/
$parentCafe = new Cafe();

$address            = $locations[0]['address'];
$city                   = $locations[0]['city'];
$state                  = $locations[0]['state'];
$zip                        = $locations[0]['zip'];
$locationName       = $locations[0]['name'];
$brewMethods        = $locations[0]['methodsAvailable'];

/*
  Get the Latitude and Longitude returned from the Google Maps Address.
*/
$coordinates = GoogleMaps::geocodeAddress( $address, $city, $state, $zip );

$parentCafe->name                   = $request->get('name');
$parentCafe->location_name  = $locationName != '' ? $locationName : '';
$parentCafe->address                = $address;
$parentCafe->city                   = $city;
$parentCafe->state                  = $state;
$parentCafe->zip                        = $zip;
$parentCafe->latitude           = $coordinates['lat'];
$parentCafe->longitude          = $coordinates['lng'];
$parentCafe->roaster                = $request->get('roaster') != '' ? 1 : 0;
$parentCafe->website                = $request->get('website');
$parentCafe->description        = $request->get('description') != '' ? $request->get('description') : '';
$parentCafe->added_by           = Auth::user()->id;

/*
  Save parent cafe
*/
$parentCafe->save();

/*
  Attach the brew methods
*/
$parentCafe->brewMethods()->sync( $brewMethods );

array_push( $addedCafes, $parentCafe->toArray() );

/*
  Now that we have the parent cafe, we add all of the other
  locations. We have to see if other locations are added.
*/
if( count( $locations ) > 1 ){
  /*
    We off set the counter at 1 since we already used the
    first location.
  */
  for( $i = 1; $i < count( $locations ); $i++ ){
    /*
      Create a cafe and grab the location
    */
    $cafe = new Cafe();

    $address            = $locations[$i]['address'];
    $city                   = $locations[$i]['city'];
    $state                  = $locations[$i]['state'];
    $zip                        = $locations[$i]['zip'];
    $locationName       = $locations[$i]['name'];
    $brewMethods        = $locations[$i]['methodsAvailable'];

    /*
      Get the Latitude and Longitude returned from the Google Maps Address.
    */
    $coordinates = GoogleMaps::geocodeAddress( $address, $city, $state, $zip );

    $cafe->parent               = $parentCafe->id;
    $cafe->name                     = $request->get('name');
    $cafe->location_name    = $locationName != '' ? $locationName : '';
    $cafe->address              = $address;
    $cafe->city                     = $city;
    $cafe->state                    = $state;
    $cafe->zip                      = $zip;
    $cafe->latitude             = $coordinates['lat'];
    $cafe->longitude            = $coordinates['lng'];
    $cafe->roaster              = $request->get('roaster') != '' ? 1 : 0;
    $cafe->website              = $request->get('website');
    $cafe->description      = $request->get('description') != '' ? $request->get('description') : '';
    $cafe->added_by             = Auth::user()->id;

    /*
      Save cafe
    */
    $cafe->save();

    /*
      Attach the brew methods
    */
    $cafe->brewMethods()->sync( $brewMethods );

    array_push( $addedCafes, $cafe->toArray() );
  }
}

/*
  Return the added cafes as JSON
*/
return response()->json($addedCafes, 201);

Много кода для прохождения! В первой строке мы инициализируем новый массив с именем addedCafes(). Здесь будут размещаться кафе, которые мы добавили в базу данных.

Затем мы берем все местоположения из запроса и создаем родительское кафе:

$locations = $request->get('locations');

/*
  Create a parent cafe and grab the first location
*/
$parentCafe = new Cafe();

$address        = $locations[0]['address'];
$city           = $locations[0]['city'];
$state          = $locations[0]['state'];
$zip                = $locations[0]['zip'];
$locationName       = $locations[0]['name'];
$brewMethods        = $locations[0]['methodsAvailable'];

Мы берем позицию 0, потому что с нашими валидациями мы точно передаем 1 позицию, и мы создаем наше родительское кафе.

Теперь мы сохраняем наше родительское кафе и синхронизируем методы варки, как показано на https://serversideup.net/many-many-relationships-laravel/

/*
  Get the Latitude and Longitude returned from the Google Maps Address.
*/
$coordinates = GoogleMaps::geocodeAddress( $address, $city, $state, $zip );

$parentCafe->name               = $request->get('name');
$parentCafe->location_name  = $locationName != '' ? $locationName : '';
$parentCafe->address                = $address;
$parentCafe->city               = $city;
$parentCafe->state              = $state;
$parentCafe->zip                    = $zip;
$parentCafe->latitude           = $coordinates['lat'];
$parentCafe->longitude          = $coordinates['lng'];
$parentCafe->roaster                = $request->get('roaster') != '' ? 1 : 0;
$parentCafe->website                = $request->get('website');
$parentCafe->description            = $request->get('description') != '' ? $request->get('description') : '';
$parentCafe->added_by           = Auth::user()->id;

/*
  Save parent cafe
*/
$parentCafe->save();

/*
  Attach the brew methods
*/
$parentCafe->brewMethods()->sync( $brewMethods );

После добавления родительского кафе мы помещаем родительское кафе в массив addCafes:

array_push( $addedCafes, $parentCafe->toArray() );

Это будет возвращено. Далее все становится немного уникальным. Сначала проверяем, есть ли еще локации:

if( count( $locations ) > 1 ){

Если есть, то мы смещаем на 1 и добавляем другие места как отдельные кафе с родительским набором кафе. Это позволяет нам сгруппировать кафе. Смещаем на 1, так как мы уже использовали первое местоположение для родительского кафе. Весь остальной код одинаков для сохранения кафе и добавления методов приготовления.

Шаг 12: добавьте функции UX в форму

Есть пара функций UX, которые я добавляю в форму. Один из них очищает форму в случае успеха и показывает уведомление. Это очень важно, потому что если пользователь хочет добавить несколько кафе за один сеанс, ему не нужно обновлять страницу. Для этого я сначала добавил getCafeAddStatus к вычисляемым свойствам на странице NewCafe.vue. Таким образом, мы можем слушать изменения.

computed: {
  brewMethods(){
    return this.$store.getters.getBrewMethods;
  },
  addCafeStatus(){
    return this.$store.getters.getCafeAddStatus;
  }
},

Затем мы добавляем следующий метод наблюдения для addCafeStatus:

watch: {
  'addCafeStatus': function(){
    if( this.addCafeStatus == 2 ){
      this.clearForm();
      $("#cafe-added-successfully").show().delay(5000).fadeOut();
    }

    if( this.addCafeStatus == 3 ){
      $("#cafe-added-successfully").show().delay(5000).fadeOut();
    }
  }
},

Что это делает, так это наблюдайте за addCafeStatus . Если он равен 2, то мы очищаем форму и показываем сообщение об успешном завершении. Метод очистки формы сбрасывает данные формы. Мы добавили этот метод в наши методы здесь:

clearForm(){
  this.name = '';
  this.locations = [];
  this.website = '';
  this.description = '';
  this.roaster = false;
  this.validations = {
    name: {
      is_valid: true,
      text: ''
    },
    locations: [],
    oneLocation: {
      is_valid: true,
      text: ''
    },
    website: {
      is_valid: true,
      text: ''
    }
  };

  this.addLocation();
}

В самом конце, после сброса информации, он добавляет местоположение в форму.

Если статус добавления кафе равен 3, то мы показываем сообщение о неудачном добавлении.

Вывод

Эта динамическая форма становится немного более конкретной для самого приложения, но, надеюсь, пример может помочь тем, кто в этом нуждается. VueJS чертовски хорошо справляется с динамическими формами благодаря своей реактивной природе. Многие функциональные возможности, наконец, собираются воедино, но теперь у нас есть действительно хорошая база, на которой мы можем абстрагировать некоторые данные и отправиться в город с еще большим количеством руководств и идей.

Конечно же, посмотрите «GitHub — serversideup/roastandbrew: помощь кофеману в поиске следующей чашки кофе. Кроме того, помогая начинающим разработчикам веб-приложений и мобильных приложений создавать одностраничные приложения и преобразовывать их в гибридные мобильные приложения. Все руководства можно найти по адресу https://serversideup.net для всего исходного кода, и обращайтесь по любым вопросам!

Привет! Мы пишем книгу по разработке приложений на основе API. Узнай первым, как только он будет готов! Зарегистрируйтесь здесь: Регистрация для разработки приложений на основе API