Backend DevelopmentFrontend DevelopmentVueJs Tutorials

Building a Simple Real estate App With Laravel and Vuejs 3 Part13

Building a Simple Real estate App With Laravel and Vuejs 3

In this article of the series “building realestate app” we will return back to property form to make the edit part and after that the property deletion.

 

 

Update & Delete Property Api

Open the PropertyController.php controller and modify the code for the update() and destroy methods like so:

app/Http/Controllers/PropertyController.php

/**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\JsonResponse
     */
    public function update(Request $request, $id)
    {
        $this->editMode = true;

        $property = Property::find($id);

        if(($validate = $this->validateProperties($request)) !== true) {
            return $validate;
        }

        $payload = [];

        foreach ($request->except(['features', 'pictures', 'accept_terms']) as $key => $val) {
            $payload[$key] = $val;
        }

        $property->update($payload);

        $property->features()->detach();

        $property->features()->attach($request->features);

        $this->storeImages($request, $property);

        return response()->json(['status' => true, 'message' => 'Property Updated Successfully', 'property' => $property]);
    }
/**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\JsonResponse
     */
    public function destroy($id)
    {
        $property = Property::with(["pictures", "features"])->find($id);

        if($property->pictures) {
            if(file_exists(public_path("/uploads/property/$property->id"))) {
                File::deleteDirectory(public_path("/uploads/property/$property->id"));
            }

            $property->pictures()->delete();
        }

        $property->features()->detach();

        $property->delete();

        return response()->json(['status' => true, 'message' => 'Property Deleted Successfully']);
    }

The update() method is similar to the store() method with a few differences. First i set the $editMode=true. Next i retrieved the target property using Property::find(). For the features it must be deleted first using the detach() method then calling attach() again:

$property->features()->detach();

$property->features()->attach($request->features);

On the other hand the destroy() method is straightforward:

  • Like the update() we retrieved the property
  • Then check for the pictures, if there is pictures i remove the picture files,
  • Then delete the features,
  • Finally delete the property record.

 

Update Property Form

The property form part on the frontend side will not need more work as most of the work is done when implementing the create functionality.

To edit your properties typically you should navigate to “/user/my-properties” url. Beside each property there are three buttons (edit, delete, view).

By clicking on the edit link the app redirects you to edit property page which is now blank, so let’s update it.

resources/js/components/pages/user/EditProperty.vue

<template>
    <div class="page-head">
        <div class="container">
            <div class="row">
                <div class="page-head-content">
                    <h1 class="page-title">Edit property #{{this.$route.params.id}}</h1>
                </div>
            </div>
        </div>
    </div>

    <!-- property area -->
    <div class="content-area submit-property" style="background-color: #FCFCFC;">&nbsp;
        <div class="container">
            <div class="clearfix" >

                <PropertyForm is-edit="1" />

            </div>
        </div>
    </div>
</template>

<script>
import PropertyForm from "../../partials/PropertyForm";

export default {
    name: "EditProperty",
    components: {PropertyForm}
}
</script>

As you see here i included <PropertyForm is-edit=”1″ /> component and pass the “is-edit” prop to indicate that this is an edit operation.

So we need to update the PropertyForm.vue:

resources/js/components/partials/PropertyForm.vue

<template>
    <div class="wizard-container">
        <div class="wizard-card ct-wizard-orange" id="wizardProperty">
            <form action="#" method="post" @submit.prevent="handleSubmit" novalidate="novalidate">
                <div class="wizard-header">
                    <h3>
                        <b>Submit</b> YOUR PROPERTY <br />
                        <small>Please fill all the fields marked as required</small>
                    </h3>
                    <div v-if="validationErrors.length" class="alert alert-danger">
                        <ul>
                            <li v-for="error of validationErrors" :key="error">{{error}}</li>
                        </ul>
                    </div>
                </div>
                <ul class="nav nav-pills">
                    <li style="width: 25%;" :class="{'active': shownStep===1}"><a>Step 1 </a></li>
                    <li style="width: 25%;" :class="{'active': shownStep===2}"><a>Step 2 </a></li>
                    <li style="width: 25%;" :class="{'active': shownStep===3}"><a>Step 3 </a></li>
                    <li style="width: 25%;" :class="{'active': shownStep===4}"><a>Finished </a></li>
                </ul>
                <div class="tab-content">
                    <div class="tab-pane" :class="{'active': shownStep===1}" id="step1" v-show="shownStep === 1">
                        <div class="row p-b-15">
                            <h4 class="info-text">Let's start with the basic information</h4>
                            <div class="col-sm-4 col-sm-offset-1">
                                <div class="picture-container">
                                    <div class="picture">
                                        <img v-if="!pictureFiles.length" src="/template/assets/img/default-property.jpg?f3345d&f3345d" class="picture-src" title="select property image" />
                                        <img v-if="pictureFiles.length > 0" :src="pictureFiles[0].image_url" class="picture-src" title="update property image" />
                                        <input type="file" id="wizard-picture" name="mainPicture" accept="image/*" @input="handleSelectMainPicture" />
                                    </div>
                                </div>
                            </div>
                            <div class="col-sm-6">
                                <div class="form-group">
                                    <label>Property title <small>(required)</small></label>
                                    <input name="title" type="text" class="form-control" placeholder="Super villa ..." v-model="form.title" />
                                </div>
                                <div class="form-group">
                                    <label>Property Type: (required)</label>
                                    <select name="status" class="form-control" v-model="form.status">
                                        <option v-for="type in propertyTypes" v-bind:key="type" :value="type">{{type}} </option>
                                    </select>
                                </div>
                                <div class="row">
                                    <div class="col-md-7">
                                        <div class="form-group">
                                            <label>Property Price / Rent <small>(required)</small></label>
                                            <input name="price" type="number" class="form-control" placeholder="3330000" v-model="form.price" />
                                        </div>
                                    </div>
                                    <div class="col-md-5" v-if="form.status === 'Rent'">
                                        <label>Rent Per <small>(for rent only)</small></label>
                                        <select name="rent_amount_per" class="form-control" v-model="form.rent_amount_per">
                                            <option>- Rent Per -</option>
                                            <option v-for="rentPer in rentAmountPerList" :key="rentPer.id" :value="rentPer.id">{{rentPer.name}}</option>
                                        </select>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label>Phone <small>(empty if you wanna use default phone number)</small></label>
                                    <input name="phone" type="text" class="form-control" placeholder="+1 473 843 7436" v-model="form.phone" />
                                </div>
                                <div class="form-group">
                                    <label>Area <small>(required)</small></label>
                                    <input name="area" type="number" class="form-control" placeholder="200 Square Meter" v-model="form.area" />
                                </div>
                            </div>
                        </div>
                    </div>
                    <!--  End step 1 -->
                    <div class="tab-pane" :class="{'active': shownStep===2}" id="step2" v-show="shownStep === 2">
                        <h4 class="info-text">How much your Property is Beautiful ?</h4>
                        <div class="row">
                            <div class="col-sm-12">
                                <div class="col-sm-12">
                                    <div class="form-group"><label>Property Description :</label>
                                        <textarea name="description" class="form-control" v-model="form.description"></textarea>
                                    </div>
                                </div>
                            </div>
                            <div class="col-sm-12">
                                <div class="col-sm-3">
                                    <div class="form-group">
                                        <label>Property Country :</label>
                                        <SelectPicker title="Select your country" :options="countries" name="country" :selected="form.country" @onChange="onCountryChange" />
                                    </div>
                                </div>
                                <div class="col-sm-3">
                                    <div class="form-group">
                                        <label>Property State :</label>
                                        <SelectPicker title="Select your state" :options="states" name="state" :selected="form.state" @onChange="onStateChange" />
                                    </div>
                                </div>
                                <div class="col-sm-3">
                                    <div class="form-group">
                                        <label>Property City :</label>
                                        <SelectPicker title="Select your city" :options="cities" name="city" :selected="form.city" @onChange="onCityChange" />
                                    </div>
                                </div>
                            </div>
                            <div class="col-sm-12 padding-top-15">
                                <div class="col-sm-2">
                                    <div class="form-group">
                                        <label>Beds :</label>
                                        <input type="number" name="bedrooms" class="form-control" v-model="form.bedrooms" >
                                    </div>
                                </div>
                                <div class="col-sm-2">

                                    <div class="form-group">
                                        <label>Baths :</label>
                                        <input type="number" name="bathrooms" class="form-control" v-model="form.bathrooms" />
                                    </div>
                                </div>
                                <div class="col-sm-2">

                                    <div class="form-group">
                                        <label>Rooms :</label>
                                        <input type="number" name="rooms" class="form-control" v-model="form.rooms" />
                                    </div>
                                </div>
                                <div class="col-sm-2">

                                    <div class="form-group">
                                        <label>Units :</label>
                                        <input type="number" name="units" class="form-control" v-model="form.units" />
                                    </div>
                                </div>
                                <div class="col-sm-2">

                                    <div class="form-group">
                                        <label>Floor number :</label>
                                        <input type="number" name="floor_number" class="form-control" v-model="form.floor_number" />
                                    </div>
                                </div>
                                <div class="col-sm-2">

                                    <div class="form-group">
                                        <label>Garages :</label>
                                        <input type="number" name="garages" class="form-control" v-model="form.garages" />
                                    </div>
                                </div>
                                <div class="col-sm-6">

                                    <div class="form-group">
                                        <label>Year Built:</label>
                                        <select name="year_built" class="form-control" v-model="form.year_built">
                                            <option value="0">- Year Built -</option>
                                            <option v-for="year in getYears()" :key="year" :value="year">{{year}}</option>
                                        </select>
                                    </div>
                                </div>
                                <div class="col-sm-6">

                                    <div class="form-group">
                                        <label>Property Finalizing:</label>
                                        <select name="property_finalizing" class="form-control" v-model="form.property_finalizing">
                                            <option>- Property Finalizing -</option>
                                            <option v-for="finalizing in propertyFinalizingList" :key="finalizing" :value="finalizing">{{finalizing}}</option>
                                        </select>
                                    </div>
                                </div>
                            </div>
                            <br /><br />
                            <h4 style="margin-left:26px">Features</h4>
                            <div class="col-sm-12 padding-top-15 padding-bottom-15">
                                <div class="col-sm-3" v-for="feature in features" v-bind:key="feature.id">
                                    <div class="form-group">

                                        <ICheckInput type="checkbox" :name="'feature'+feature.id" :value="feature.id" :text="feature.title" v-on:onChecked="handleOnSelectFeature" v-on:onUnchecked="handleOnDeselectFeature" :defaultChecked="form.features.includes(feature.id)" />

                                    </div>
                                </div>

                            </div>

                            <br />
                        </div>
                    </div>
                    <!-- End step 2 -->
                    <div class="tab-pane" :class="{'active': shownStep===3}" id="step3" v-show="shownStep === 3">
                        <h4 class="info-text">Give us some images and video</h4>
                        <div class="row">
                            <div class="col-sm-6">
                                <div class="form-group">
                                    <label>Choose Images :</label>
                                    <input class="form-control" type="file" name="pictures" multiple accept="image/*" @input="handleSelectOtherPictures" />
                                    <p class="help-block">Select multiple images for your property .</p>
                                    <ul v-if="pictureFiles.length > 1" class="pictures">
                                        <li v-for="picture in pictureFiles.slice(1, pictureFiles.length)" :key="picture.id">
                                            <img :src="picture.image_url" width="100" height="80" />
                                        </li>
                                    </ul>
                                </div>
                            </div>
                            <div class="col-sm-6">
                                <div class="form-group">
                                    <label>Property video :</label>
                                    <input class="form-control" placeholder="http://www.youtube.com" name="youtube_video" type="text" v-model="form.youtube_video" />
                                </div>
                            </div>
                        </div>
                    </div>
                    <!--  End step 3 -->
                    <div class="tab-pane" :class="{'active': shownStep===4}" id="step4" v-show="shownStep === 4">
                        <h4 class="info-text">Finished and submit</h4>
                        <div class="row">
                            <div class="col-sm-12">
                                <div class="">
                                    <p>
                                        <label><strong>Terms and Conditions</strong></label>
                                        By accessing or using  GARO ESTATE services, such as
                                        posting your property advertisement with your personal
                                        information on our website you agree to the
                                        collection, use and disclosure of your personal information
                                        in the legal proper manner
                                    </p>

                                    <ICheckInput type="checkbox" name="accept_terms" value="1" text="Accept terms and conditions." v-on:onChecked="handleAcceptTerms" v-on:onUnchecked="handleRefuseTerms" :default-checked="form.accept_terms" />

                                </div>
                            </div>
                        </div>
                    </div>
                    <!--  End step 4 -->
                </div>
                <div class="wizard-footer">
                    <div class="pull-right">
                        <input type='button' class='btn btn-next btn-primary' name='next' value='Next' @click="moveForward" v-show="shownStep >= 1 && shownStep < 4" />
                        <input type='submit' class='btn btn-primary ' name='finish' :value="!this.$route.params.id ? 'Finish' : 'Update'" :disabled="!form.accept_terms" v-show="shownStep === 4" />
                    </div>

                    <div class="pull-left">
                        <input type='button' class='btn btn-previous btn-default' name='previous' value='Previous' @click="moveBackward" v-show="shownStep > 1" />
                    </div>
                    <div class="clearfix"></div>
                </div>
            </form>
        </div>
        <!-- End submit form -->
    </div>
</template>

<script>
import {useRoute} from "vue-router";
import ICheckInput from "./ICheckInput";
import SelectPicker from "./SelectPicker";
import {useSetupFormWizard} from "../../composables/useSetupFormWizard";
import {useSubmitPropertyForm} from "../../composables/useSubmitPropertyForm";
import {useLoadStaticData} from "../../composables/useLoadStaticData";

export default {
    name: "PropertyForm",
    props: ["isEdit"],
    components: {SelectPicker, ICheckInput},
    setup(props) {
        const route = useRoute();

        const {form, handleSubmit, handleSelectMainPicture,
            handleSelectOtherPictures, handleAcceptTerms, handleRefuseTerms,
            handleOnDeselectFeature, handleOnSelectFeature, validationErrors, pictureFiles} = useSubmitPropertyForm(props.isEdit == '1');

        const {getYears, rentAmountPerList, propertyFinalizingList, propertyTypes,
            features, countries, states, cities, handleSelectCountry, handleSelectState,
            handleSelectCity, selectedCountry, selectedState, selectedCity, loadStates, loadCities} = useLoadStaticData({selectedCountryId: form.country, selectedStateId: form.state, selectedCityId: form.city});

        const {shownStep, moveForward, moveBackward} = useSetupFormWizard();

        const onCountryChange = e => {
            handleSelectCountry(e);
            form.country = selectedCountry.value;
            form.state = '';
            form.city = '';
        }

        const onStateChange = e => {
            handleSelectState(e);
            form.state = selectedState.value;
            form.city = '';
        }

        const onCityChange = e => {
            handleSelectCity(e);
            form.city = selectedCity.value;
        }

        if(props.isEdit == '1') {
            setTimeout(() => {
                window.axios.get(`/api/property/${route.params.id}`).then(res => {
                    if(res.data.status) {
                        const property = res.data.property;
                        for(let key in property) {
                            if(form.hasOwnProperty(key)) {
                                if(key === 'country' || key === 'state' || key === 'city') {
                                    form[key] = property[key] ? property[key].id : 0;
                                    if(key === 'country') {
                                        loadStates(form[key]);
                                    }

                                    if(key === 'state') {
                                        loadCities(form[key], form.country);
                                    }
                                } else if(key === 'features') {
                                    form[key] = property[key] ? property[key].map(f => f.id) : [];
                                } else if(key === 'pictures') {
                                    pictureFiles.value = property[key] ? property[key] : [];
                                } else {
                                    form[key] = property[key];
                                }
                            }
                        }
                    }
                });
            }, 500);
        }

        return {
            getYears,
            shownStep,
            moveForward,
            moveBackward,
            propertyTypes,
            rentAmountPerList,
            propertyFinalizingList,
            features,
            countries,
            states,
            cities,
            onCountryChange,
            onStateChange,
            onCityChange,
            form,
            handleSubmit,
            handleSelectMainPicture,
            handleSelectOtherPictures,
            handleAcceptTerms,
            handleRefuseTerms,
            handleOnSelectFeature,
            handleOnDeselectFeature,
            validationErrors,
            pictureFiles
        }
    }
}
</script>

<style scoped>
 .btn[disabled] {
     background-color: #ccc;
     color: #000;
}

 .pictures li {
     display: inline;
 }
</style>

I added some modifications to this component, first i included “isEdit” to the props array. Then i modified the setup(props) function to accept the props argument so that we can access the props inside setup, in our case we will check for props.isEdit.

If the props.isEdit==1 then this an edit mode and i made an http request to fetch the current property to be loaded as shown in the above code:

if(props.isEdit == '1') {
            setTimeout(() => {
                window.axios.get(`/api/property/${route.params.id}`).then(res => {
                         ....
                         ....
               }
             });
}

Then in the template i displayed the pictures in both the main picture and the other pictures.

One final thing for the update to work is to modify the handleSubmit() function in useSubmitPropertyForm.js

resources/js/composables/useSubmitPropertyForm.js

import {reactive, ref, watch} from "vue";
import {useToast} from "vue-toastification";
import {useRoute, useRouter} from "vue-router";

export const useSubmitPropertyForm = (isEdit = false) => {
    const toast = useToast();
    const router = useRouter();
    const route = useRoute();

  const form = reactive({
      title: '',
      description: '',
      status: 'Sale',
      price: '',
      rent_amount_per: '',
      area: '',
      country: 0,
      state: 0,
      city: 0,
      bedrooms: 0,
      bathrooms: 0,
      rooms: 0,
      garages: 0,
      units: 0,
      floor_number: 0,
      year_built: 0,
      property_finalizing: '',
      phone: '',
      youtube_video: '',
      features: [],
      pictures: [],
      accept_terms: (!!window.localStorage.getItem("terms_accepted"))
  });

  const pictureFiles = ref([]);

  const validationErrors = ref([]);

  const handleSelectMainPicture = e => {
        form.pictures = [...form.pictures, e.target.files[0]];
  }

  const handleSelectOtherPictures = e => {
      form.pictures = [...form.pictures, ...e.target.files];
  }

  const handleOnSelectFeature = val => {
      form.features = form.features.find(v => v === parseInt(val)) !== undefined ? form.features : [...form.features, parseInt(val)];
  }

  const handleOnDeselectFeature = val => {
        form.features = form.features.filter(v => v !== parseInt(val));
  }

  const handleAcceptTerms = val => {
      form.accept_terms = true;
  }

    const handleRefuseTerms = val => {
        form.accept_terms = false;
    }

  const handleSubmit = () => {
      const { formData, headers } = getPayload();

      window.localStorage.setItem("terms_accepted", 1);

      window.axios.post(`/api/property${isEdit ? '/' + route.params.id : ''}`, formData, { headers }).then(response => {
          handleResponse(response);
      }).catch(error => {
          handleResponse(error.response);
      });
  };

  const getPayload = () => {
      const formData = new FormData();

      for(let field in form) {
          if(field === 'features' || field === 'pictures') {
              form[field].forEach(key => {
                  formData.append(`${field}[]`, key);
              });
          } else {
              formData.append(field, form[field]);
          }
      }

      if(isEdit) {
          formData.append("_method", "PUT");
      }

      const headers = { 'Content-Type': 'multipart/form-data' };

      return {formData, headers};
  }

  const handleResponse = response => {
      validationErrors.value = [];

      if(response.data.status) {
          toast.success(response.data.message);
          router.push("/user/my-properties");
          return;
      }

      if(response.data.errors) {
          for(let field in response.data.errors) {
              validationErrors.value = [...validationErrors.value, response.data.errors[field][0]];
          }
      }
  }

  return {
      form,
      handleSelectMainPicture,
      handleSelectOtherPictures,
      handleOnSelectFeature,
      handleOnDeselectFeature,
      handleAcceptTerms,
      handleRefuseTerms,
      handleSubmit,
      validationErrors,
      pictureFiles
  }
};

With this update in place now go to your properties page and click any property edit link, now you should see property is already populated in each field and you can click update.

 

Deleting Properties

The delete property functionality located in PropertyTemplate.vue so update it with this code:

resources/js/components/partials/PropertyTemplate.vue

<template>
    <div class="box-two proerty-item">
        <div class="item-thumb">
            <router-link :to="getPropertyDetailUrl()"><img :src="property.pictures[0].image_url" :alt="property.title"></router-link>
        </div>

        <div class="item-entry overflow ">
            
            <h5><router-link :to="getPropertyDetailUrl()"> {{property.title}} </router-link></h5>
            <div class="dot-hr"></div>
            <span class="pull-left"><b> Area :</b> {{property.area}}m </span>
            <span class="proerty-price pull-right"> $ {{formatMoney(property.price)}}</span>
            <p style="display: none;" v-if="property.description">{{property.description}}</p>
            <div class="property-icon">
                <span v-for="(feature, index) in getFeatures()" :key="index">
                    <img :src="'/template/assets/img/icon/' + feature.icon"> ({{feature.val}}){{index === getFeatures().length - 1 ? '' : '|'}}
                </span>

                <div class="dealer-action pull-right" v-if="show_actions">
                    <router-link :to="`/user/edit-property/${property.id}`" class="button">Edit </router-link>
                    <a href="#" @click.prevent="deleteProperty" class="button delete_user_car">Delete</a>
                    <router-link :to="getPropertyDetailUrl()" class="button">View</router-link>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import {useToast} from "vue-toastification";
import {formatMoney, slugify} from "../../api/helpers";

export default {
    name: "PropertyTemplate",
    props: ["property", "show_actions"],
    emits: ["onPropertyDeleted"],
    setup(props, context) {
        const toast = useToast();

        const getPropertyDetailUrl= function () {
            return `/property/${props.property.id}/${slugify(props.property.title)}`;
        }

        const getFeatures = function () {
            let features = [];
            if(props.property.bedrooms) {
                features = [...features, {icon: 'bed.png', val: props.property.bedrooms}];
            }

            if(props.property.bathrooms) {
                features = [...features, {icon: 'shawer.png', val: props.property.bathrooms}];
            }

            if(props.property.garages) {
                features = [...features, {icon: 'cars.png', val: props.property.garages}];
            }

            return features;
        }

        const deleteProperty = function () {
            if(window.confirm("Are you sure to delete this property?")) {
                window.axios.delete(`/api/property/${props.property.id}`).then(response => {
                    if (response.data.status) {
                        toast.success(response.data.message);
                        context.emit('onPropertyDeleted', props.property.id);
                    }
                });
            }
        }

        return {
            formatMoney,
            getPropertyDetailUrl,
            getFeatures,
            deleteProperty
        }
    }
}
</script>

<style scoped>
    .add-to-fav {
        background: #a6a3a3;
    }

    .fav-selected {
        color: #FDC600;
        border-color: #FDC600;
    }
</style>

I updated the deleteProperty() function to make a delete request to the destroy property endpoint, on successful response i emit “onPropertyDeleted” event with property id. We will use listen for this custom event to reload properties in user properties page.

resources/js/components/pages/user/MyProperties.vue

<template>
    <div class="page-head">
        <div class="container">
            <div class="row">
                <div class="page-head-content">
                    <h1 class="page-title">Your Properties</h1>
                </div>
            </div>
        </div>
    </div>

    <div class="content-area recent-property" style="background-color: #FFF;">
        <div class="container">
            <div class="row">

                <div class="col-md-9 pr-30 padding-top-40 properties-page user-properties">

                    <div class="section">

                        <SortingBar :per_page="params.per_page" :default_sort="params.sorting" :show_layout="false" container_class="pl0 pr-10" sorting_class="pull-left" per_page_class="pull-right"
                                    @onSelectPerPage="handlePerPage" @onSelectSort="handleSorting"
                        />

                    </div>

                    <div class="section" v-if="properties">
                        <div id="list-type" class="proerty-th-list">
                            <div class="col-md-4 p0" v-for="property of properties.data" :key="property.id">
                                <PropertyTemplate :property="property" :show_actions="true" @onPropertyDeleted="onPropertyDeleted" />
                            </div>
                        </div>
                    </div>

                    <div class="section" v-if="properties">
                        <div class="pull-right">
                            <Pagination :item="properties" @onPaginate="paginate" />
                        </div>
                    </div>

                </div>

                <div class="col-md-3 p0 padding-top-40">
                    <div class="blog-asside-right">
                        <div class="panel panel-default sidebar-menu wow fadeInRight animated" >

                        </div>

                        <div class="panel panel-default sidebar-menu wow fadeInRight animated">

                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import {useRouter, useRoute} from "vue-router";
import PropertyTemplate from "../../partials/PropertyTemplate";
import Pagination from "../../partials/Pagination";
import SortingBar from "../../partials/SortingBar";
import {useFetchListings} from "../../../composables/useFetchListings";

export default {
    name: "MyProperties",
    components: {SortingBar, Pagination, PropertyTemplate},
    setup() {
        const router = useRouter();
        const route = useRoute();

        const {params, loadData, properties} = useFetchListings('/api/user_properties');

        const paginate = page => {
            params.page = page;
            loadData();
            const query = {...route.query, page};
            router.push({ path: route.path, query });
        };

        const handleSorting = (sortObj) => {
            const rawObject = {...sortObj};

            params.sorting.sortBy = rawObject.sortBy;
            params.sorting.sortOrder = rawObject.sortOrder;
            params.page = 1;
            loadData();

            const query = {...route.query, page: 1, sorting_field: rawObject.sortBy, sorting_order: rawObject.sortOrder};
            router.push({ path: route.path, query });
        }

        const handlePerPage = perPage => {
            params.per_page = perPage;
            params.page = 1;
            loadData();
            const query = {...route.query, per_page: params.per_page, page: 1};
            router.push({ query});
        }

        const onPropertyDeleted = pid => {
            //properties.value.data = properties.value.data.filter(p => p.id !== parseInt(pid));
            loadData();
        }

        loadData();

        return {
            properties,
            params,
            paginate,
            handlePerPage,
            handleSorting,
            onPropertyDeleted
        }
    }
}
</script>

 

Continue to part 14: Favorites>>>

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Sopha
Sopha
1 month ago

Big thanks for sharing free for your sources code