guggio
guggio

Reputation: 221

Vue.js not working after vue-router is implemented

This is the code I'm using to try creating a single page app. I'm reading about vue router and I've tried to apply it to my project. I'm not sure what's wrong with the code, but I'm not able to see the page where the app run. I get some errors on chrom console, but this happen after I've added vue router to my project. Any help to fix it?

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
    <link href="https://fonts.googleapis.com/css2?family=Courgette&display=swap" rel="stylesheet">


    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>

    <title>C safe!</title>
  </head>
  <body>

    <style>
    h1{
      font-family: 'Courgette', cursive;
    }
    .list-group {
      max-height: 300px;
      margin-bottom: 10px;
      overflow:scroll;
      -webkit-overflow-scrolling: touch;
    }
    #map {
      height: 400px;
    }
    </style>
    <div class="container-fluid bg-light p-0" id="app">

      <div class="row">
        <div class="col-sm-12 col-md-12 col-lg-12 p-5">
        <ul class="nav">
          <router-link to="/">
            <li class="nav-item">
              <a class="nav-link" href="#">Home</a>
            </li>
          </router-link>
        </ul>
        </div>
      </div>

    <script type="text/x-template" id="search-bar">
      <div class="row justify-content-center m-0" style="height:100vh;">
        <div class="col-sm-12 col-md-8 col-lg-8 p-5 mx-auto">
          <h1 class="mt-5 mb-3 text-center">C</h1>
          <div class="input-group">
              <input type="email" class="form-control rounded-0" v-on:change="instantSearch()" v-model="q" placeholder="Cerca nelle vicinanze es: Pizzeria">
            <div class="input-group-append">
              <button class="btn btn-outline-success rounded-0" v-on:click="instantSearch()">Cerca</button>
            </div>
          </div>
          <ul v-if="resultSet" class="list-group rounded-0">
            <small v-if="q" class="list-group-item rounded-0"><a class="text-muted" href="#" v-on:click="resetSearch()">Annulla</a></small>
            <router-link to="/results">
              <a v-for="result in resultSet" :key="result.id" v-on:click="expandMap(result.lat, result.lon)" href="#" class="list-group-item rounded-0" :place="result.display_name">{{ result.display_name }}</a>
            </router-link>
          </ul>
          <ul class="nav">
            <li class="nav-item">
              <a class="nav-link" href="#">FAQ</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Aggiungi la tua attività</a>
            </li>
          </ul>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="result-detail">
      <div class="collapse" id="map-collapsable">
        <div class="row m-0 results-map">
          <div class="col-sm-12 col-md-8 col-lg-8 p-0" id="map"></div>
          <div v-for="place in placeData" class="col-sm-12 col-md-4 col-lg-4">
          {{ place.lat }} {{ place.lng }}
          </div>
        </div>
      </div>
    </script>

    <router-view></router-view>
    </div>
<!-- TODO: Vue components -->
   
    <script src="app.js"></script>
  </body>
</html>

This is the JS vue code

window.onload = function(){
  Vue.component('search-bar',{
    template: '#search-bar',
    data(){
      return {}
    }
  });

  Vue.component('view-result',{
    template: '#result-detail',
    data(){
      return {}
    }
  });

  const searchbar = {template: 'search-bar'}
  const result = {template: 'view-result'}

  const routes = [
    {path: '/', component: searchbar},
    {path: '/results', component: result}
  ];

  const router = new VueRouter({
    routes // short for `routes: routes`
  });

  const web = new Vue({
    router,
    el: '#app',
    data: {
      pageData: [],
      resultSet: [],
      placeData: [],
      q: '',
      name: '',
    },
    mounted: function(){
      //this.initPage();
    },
    ready: function(){

    },
    computed: {

    },
    watch: {
      q: function(val, oldVal){
        this.instantSearch();
      }
    },
    methods: {
      instantSearch: function(){
        axios.get('https://nominatim.openstreetmap.org/search?q='+this.q+'&format=json').then( (places) => {
          console.log(places);
          this.resultSet = [];
          places.data.forEach( (item, i) => {
            this.resultSet.push(item);
          });
        });
      },
      resetSearch: function(){
        this.resultSet = [];
        this.q = '';
      },
      expandMap: function(lat, lng){
        let collapsable = document.getElementById('map-collapsable');
        console.log(lat, lng);
        //$(collapsable).collapse();
        this.placeData.push({lat: lat, lng: lng});
      },
      initMap: function(data){

      }
    }
  }).$mount('#app');

}

The errors I get are the following:

vue.js:634 [Vue warn]: Property or method "result" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

(found in <Root>)
warn @ vue.js:634
warnNonPresent @ vue.js:2047
has @ vue.js:2092
eval @ VM258:3
Vue._render @ vue.js:3551
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
Vue._init @ vue.js:5012
Vue @ vue.js:5078
window.onload @ app.js:28
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Error in render: "TypeError: Cannot read property 'display_name' of undefined"

(found in <Root>)
warn @ vue.js:634
logError @ vue.js:1893
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
Vue._init @ vue.js:5012
Vue @ vue.js:5078
window.onload @ app.js:28
load (async)
(anonymous) @ app.js:1
vue.js:1897 TypeError: Cannot read property 'display_name' of undefined
    at Proxy.eval (eval at createFunction (vue.js:11649), <anonymous>:3:1557)
    at Vue._render (vue.js:3551)
    at Vue.updateComponent (vue.js:4067)
    at Watcher.get (vue.js:4478)
    at new Watcher (vue.js:4467)
    at mountComponent (vue.js:4074)
    at Vue.$mount (vue.js:9044)
    at Vue.$mount (vue.js:11944)
    at Vue._init (vue.js:5012)
    at new Vue (vue.js:5078)
logError @ vue.js:1897
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
Vue._init @ vue.js:5012
Vue @ vue.js:5078
window.onload @ app.js:28
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Cannot find element: #app
warn @ vue.js:634
query @ vue.js:5666
Vue.$mount @ vue.js:11882
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Property or method "result" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

(found in <Root>)
warn @ vue.js:634
warnNonPresent @ vue.js:2047
has @ vue.js:2092
eval @ VM258:3
Vue._render @ vue.js:3551
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Error in render: "TypeError: Cannot read property 'display_name' of undefined"

(found in <Root>)
warn @ vue.js:634
logError @ vue.js:1893
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1
vue.js:1897 TypeError: Cannot read property 'display_name' of undefined
    at Proxy.eval (eval at createFunction (vue.js:11649), <anonymous>:3:1557)
    at Vue._render (vue.js:3551)
    at Vue.updateComponent (vue.js:4067)
    at Watcher.get (vue.js:4478)
    at new Watcher (vue.js:4467)
    at mountComponent (vue.js:4074)
    at Vue.$mount (vue.js:9044)
    at Vue.$mount (vue.js:11944)
    at window.onload (app.js:83)
logError @ vue.js:1897
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1

I don't know why but before I create the components and try to use the vue-router, all was working fine.

Upvotes: 0

Views: 433

Answers (1)

tony19
tony19

Reputation: 138696

There are a few problems:

  1. The script type=text/x-templates need to be moved outside of the app div. Otherwise, the template would be processed as part of the app's template, resulting in the undefined errors you observed in the console.

  2. Since your Vue declaration already specifies el: #app, you need to remove .$mount('#app').

  3. The route paths incorrectly specify a literal string template in: { template: 'search-bar' } and { template: 'result-detail' }. That should be { template: '<search-bar />' } and { template: '<result-detail />' } respectively.

  4. The q and resultSet data props should be moved into the search-bar component. Similarly, the placeData data prop should be moved into the result-detail component.

Demo:

window.onload = function(){
  Vue.component('search-bar',{
    template: '#search-bar',
    data(){
      return {
        resultSet: [],
        q: '',
      }
    }
  });

  Vue.component('view-result',{
    template: '#result-detail',
    data(){
      return {
        placeData: [],
      }
    }
  });

  const searchbar = {template: '<search-bar />'}
  const result = {template: '<view-result />'}

  const routes = [
    {path: '/', component: searchbar},
    {path: '/results', component: result}
  ];

  const router = new VueRouter({
    routes // short for `routes: routes`
  });

  const web = new Vue({
    router,
    el: '#app',
    data: {
      pageData: [],
      name: '',
    },
    mounted: function(){
      //this.initPage();
    },
    ready: function(){

    },
    computed: {

    },
    watch: {
      q: function(val, oldVal){
        this.instantSearch();
      }
    },
    methods: {
      instantSearch: function(){
        axios.get('https://nominatim.openstreetmap.org/search?q='+this.q+'&format=json').then( (places) => {
          console.log(places);
          this.resultSet = [];
          places.data.forEach( (item, i) => {
            this.resultSet.push(item);
          });
        });
      },
      resetSearch: function(){
        this.resultSet = [];
        this.q = '';
      },
      expandMap: function(lat, lng){
        let collapsable = document.getElementById('map-collapsable');
        console.log(lat, lng);
        //$(collapsable).collapse();
        this.placeData.push({lat: lat, lng: lng});
      },
      initMap: function(data){

      }
    }
  })

}
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-router.js"></script>

<style>
  h1{
    font-family: 'Courgette', cursive;
  }
  .list-group {
    max-height: 300px;
    margin-bottom: 10px;
    overflow:scroll;
    -webkit-overflow-scrolling: touch;
  }
  #map {
    height: 400px;
  }
</style>

<div class="container-fluid bg-light p-0" id="app">

  <div class="row">
    <div class="col-sm-12 col-md-12 col-lg-12 p-5">
      <ul class="nav">
        <router-link to="/">
          <li class="nav-item">
            <a class="nav-link" href="#">Home</a>
          </li>
        </router-link>
      </ul>
    </div>
  </div>

  <router-view></router-view>
</div>

<script type="text/x-template" id="search-bar">
  <div class="row justify-content-center m-0" style="height:100vh;">
    <div class="col-sm-12 col-md-8 col-lg-8 p-5 mx-auto">
      <h1 class="mt-5 mb-3 text-center">C</h1>
      <div class="input-group">
        <input type="email" class="form-control rounded-0" v-on:change="instantSearch()" v-model="q" placeholder="Cerca nelle vicinanze es: Pizzeria">
        <div class="input-group-append">
          <button class="btn btn-outline-success rounded-0" v-on:click="instantSearch()">Cerca</button>
        </div>
      </div>
      <ul v-if="resultSet" class="list-group rounded-0">
        <small v-if="q" class="list-group-item rounded-0"><a class="text-muted" href="#" v-on:click="resetSearch()">Annulla</a></small>
        <router-link to="/results">
          <a v-for="result in resultSet" :key="result.id" v-on:click="expandMap(result.lat, result.lon)" href="#" class="list-group-item rounded-0" :place="result.display_name">{{ result.display_name }}</a>
        </router-link>
      </ul>
      <ul class="nav">
        <li class="nav-item">
          <a class="nav-link" href="#">FAQ</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Aggiungi la tua attività</a>
        </li>
      </ul>
    </div>
  </div>
</script>

<script type="text/x-template" id="result-detail">
  <div class="collapse" id="map-collapsable">
    <div class="row m-0 results-map">
      <div class="col-sm-12 col-md-8 col-lg-8 p-0" id="map"></div>
      <div v-for="place in placeData" class="col-sm-12 col-md-4 col-lg-4">
        {{ place.lat }} {{ place.lng }}
      </div>
    </div>
  </div>
</script>

Upvotes: 2

Related Questions