I have some google maps api that i've already craeted in javascript, but, for some time my collagues decided to use vue framework on the apps.
I tried to put my initMap of my googlemaps javascript inside vue methods and trye to call it on windows.initmap outside vue app, but it doesn't work,
here are my javascript code bellow
let base_url = '{{ envx('APP_BASE_URL') }}';
let cdn = '{{ envx('CDN_ENDPOINT') }}';
let endpoint = '{{ envx('API_ENDPOINT') }}';
addEventListener('load', () => {
const {
createApp
} = Vue;
const initialState = () => {
return {
containerClass: 'container-grid',
loading: false,
properties: <?= json_encode($list_properti) ?>,
filter: {
page: 1,
limit: 12,
keyword: '',
harga: '',
status_unit: '',
jenis: '',
id_propinsi: '',
}
}
}
const app = createApp({
data() {
return initialState()
},
methods: {
checkData() {
console.log(this.properties.DATA);
},
getPropertiImage(imageUrl) {
const urlOnly = `{{ file_exists('${imageUrl}') }}`
if (urlOnly) return base_url + 'assets/img/no-data.png'
if (imageUrl === null) return base_url + 'assets/img/no-data.png'
const checkImage = imageUrl.split("")
const getFlag = [checkImage[0], checkImage[1]].join("")
if (getFlag !== '1|') return base_url + 'assets/img/no-data.png'
return imageUrl.replace('1|', cdn + '?key=')
},
setToBillions(item) {
let price = item;
let idrPrices = `{{ rupiah((float) '${price}') }}`;
let prices = idrPrices.split('.');
if (prices.length > 3) {
return [prices[0], prices[1]].join('.') + " Juta";
}
return idrPrices;
},
cicilan(val) {
let cicilan = (val / 1000000).toFixed(1);
if (cicilan < 1) {
return 'Rp.' + (cicilan * 1000).toLocaleString('id-ID') + 'rb/bln';
}
return 'Rp.' + cicilan.toLocaleString('id-ID') + 'jt/bln';
},
getAvatar(url) {
if (url) {
let explodeAva = url.split('|member');
if (explodeAva.length == 2) {
return cdn + '?key=member' + explodeAva[1];
}
return url;
}
return base_url + 'assets/img/avatar/1552FBA78C75D6FBA33F.png';
},
changePage(id) {
if (this.loading) {
return false;
}
document.getElementById('container-loading').scrollIntoView({
behavior: 'auto',
block: 'start',
inline: 'nearest'
});
this.filter.page = id;
this.updateContent()
this.initMap()
},
async initMap() {
const centerPosition = {
lat: -1.6160679698214473,
lng: 117.38277669882174
}
let map = new google.maps.Map(document.getElementById("container-map"), {
center: centerPosition,
zoom: 5,
});
const areaProperties = []
for (const properti of this.properties.DATA) {
const exampleUrl = `{{ envx('CDN_ENDPOINT') }}?key=`;
let imageUrl = properti.GBR1;
imageUrl = imageUrl.replace('1|', exampleUrl);
const urlAvatar = ``
let imageMember = properti.AVATAR_MEMBER;
const imageAvatar = imageMember.replace('1|', imageMember);
const propertiAreas = {
position: new google.maps.LatLng(properti.LATITUDE, properti.LONGITUDE),
content: ` <template v-if="!loading" v-for="(properti, index) in properties.DATA">
<div class="card card-container card-shadow card--radius mb-2">
<div class="img-container">
<div class="img-top">
<div class="badge-report bg-colors-blue" v-html="properti.JENIS_PROPERTI"></div>
</div>
<img class="card-img-top img-card" v-bind:src="'' + getPropertiImage(properti.GBR1)"
alt="''+ properti.NAMA">
</div>
<div class="card--body m-4">
<small class="d-flex gap-2 align-items-center text-dim">
<img src="assets/img/shape/location.png" class="icon-location" height="12">
<div style="width: 100%; text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap; "
v-html="properti.ALAMAT"></div>
</small>
<h4 v-html="properti.NAMA"></h4>
<small class="text-dim">Mulai dari</small>
<h3 v-html="'Rp. '+ setToBillions(properti.HARGA)"></h3>
<small class="text-dim d-block">Cicilan dari <b class="text-black"
style="font-family: 'Futura'" v-html="cicilan(properti.CICILAN)"></b></small>
<small class="text-dim d-block">Suku Bunga <b class="text-black"
style="font-family: 'Futura'" v-html="'Dari '+ properti.BUNGA + '%'"></b></small>
<small class="d-flex gap-2 align-items-center mt-2"
style="font-size: 12px; color: var(--c-blue); font-family: 'FuturaMD';">
<img src="'' + getAvatar(properti.AVATAR_MEMBER)" height="25" class="rounded-circle">
<div v-html="properti.NAMA_AGEN"></div>
</small>
</div>
<div class="card-label--foot bandingkan-button" role="button" #onclick="handleCompare()">
Bandingkan
</div>
</div>
</template>
`
}
areaProperties.push(propertiAreas)
}
var infowindow = new google.maps.InfoWindow();
const icon = {
url: 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by #fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M36.8 192H603.2c20.3 0 36.8-16.5 36.8-36.8c0-7.3-2.2-14.4-6.2-20.4L558.2 21.4C549.3 8 534.4 0 518.3 0H121.7c-16 0-31 8-39.9 21.4L6.2 134.7c-4 6.1-6.2 13.2-6.2 20.4C0 175.5 16.5 192 36.8 192zM64 224V384v80c0 26.5 21.5 48 48 48H336c26.5 0 48-21.5 48-48V384 224H320V384H128V224H64zm448 0V480c0 17.7 14.3 32 32 32s32-14.3 32-32V224H512z"/></svg>'
),
scaledSize: new google.maps.Size(20, 20)
}
let marker, i;
for (i = 0; i < areaProperties.length; i++) {
marker = new google.maps.Marker({
position: areaProperties[i].position,
icon: icon,
map: map,
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(areaProperties[i].content);
infowindow.open(map, marker);
}
})(marker, i));
}
},
// async updateContent() {
async updateContent() {
this.loading = true;
this.containerClass = 'w-full'
const filterData = this.filter;
const filterStrings = []
const lastKey = Object.keys(filterData).pop();
for (const key in filterData) {
if (filterData[key] !== "" || filterData[key] !== null) {
filterStrings.push(key)
filterStrings.push('=')
filterStrings.push(filterData[key])
if (key !== lastKey) {
filterStrings.push('&')
}
}
}
//FIXME string zero values
const params = filterStrings.join('')
await $.ajax({
type: 'get',
dataType: 'json',
url: base_url + 'api/properti/list-properti?' + params,
success: res => {
this.properties = res;
}
})
this.loading = false;
this.containerClass = 'container-grid'
}
}
}).mount('#app')
window.initMap = app.initMap();
})
And here is the error that i got
How could i solve this?
You shouldn't call window.initMap = app.initMap(); after creating the Vue instance but rather in the mounted lifecycle hook:
mounted() {
window.initMap = app.initMap();
}
Related
i'm trying to get vue-router to work with blogger feeds json api, i managed to make it work but on reload it goes back to the first page, i tried to add html components and template in routes parameter but it did not work, i tried everything i begun to wonder if it is even possible, here is my code:
new Vue({
el: '#app',
router: new VueRouter({}),
vuetify: new Vuetify({}),
data() {
return {
feedAPI: '/feeds/posts/default?alt=json&start-index=',
items_all: [],
items: [],
Totalposts: null,
Totalpages: null,
Startindex: 1,
pageNumber: null,
keyword: '',
results: [],
Postsperpage: 5,
}
},
methods: {
getPosts() {
axios.get(this.feedAPI + this.Startindex + '&max-results=' + this.Postsperpage).then(async (response) => {
const items = await response.data;
this.items_all = items.feed;
this.items = this.items_all.entry;
var totalPosts = this.items_all.openSearch$totalResults.$t;
this.Totalposts = totalPosts;
var itemsPerPage = this.items_all.openSearch$itemsPerPage.$t;
this.Postsperpage = itemsPerPage;
var totalPages = Math.ceil(this.Totalposts / this.Postsperpage);
this.Totalpages = totalPages;
this.$router.push({
query: Object.assign({}, this.$route.query.pageNumber, {
page: this.pageNumber || 1
})
});
this.$nextTick(() => {
this.pageNumber
});
})
},
onPageChange() {
this.Startindex = Math.ceil((this.pageNumber * this.Postsperpage) - (this.Postsperpage - 1));
this.getPosts();
},
top() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
},
getResults() {
if (this.keyword.length > 2) {
axios.get("/feeds/posts/default?alt=json&q=" + this.keyword).then(res => (this.results = res.data.feed.entry)).catch(err => console.log(err));
}
}
},
watch: {
keyword: function(newVal) {
if (newVal.length > 3) {
this.getResults();
}
}
},
computed: {},
created() {
this.getResults()
},
mounted() {
this.getPosts();
}
});
for the html :
<v-text-field v-model="keyword" #input="getResults" placeholder="Type to Search"></v-text-field>
<div v-if="getResults">
<span v-for="result in results">
<a v-for="i in result.link" v-if="i.rel == 'alternate'" :href="i.href" :title="result.title.$t" v-html="i.title"></a>
<br />
</span>
</div>
<div v-for="item in items">
<h3><a v-for="i in item.link" v-if="i.rel == 'alternate'" :href="i.href" :title="item.title.$t" v-html="i.title"></a></h3>
</div>
<v-pagination v-model="pageNumber" :length="Totalpages" #input="onPageChange" prev-icon="mdi-menu-left" next-icon="mdi-menu-right" v-on:click.native="top"></v-pagination>
I am using laravel livewire for my website and on that web, I created a multi-step form where I have to fetch google maps API in the first step. as I know I have to use wire: ignore when using third-party JavaScript library in Livewire component. but the problem comes when I switch from form step 2 to step 1, where google map is not rendered
This is my livewire view.
<div wire:ignore>
<div id="address-map-container" class="mt-2" style="width:100%;height:320px; ">
<div style="width: 100%; height: 100%" id="address-map"></div>
</div>
</div>
<!-- End Google Maps -->
<!-- Seach in google maps -->
<input type="text" wire:model.lazy="address_address" id="address-input"
class="mt-4 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md map-input"
placeholder="Search in Google Maps">
<input type="hidden" wire:model.lazy="address_latitude" id="address-latitude" value="0" />
<input type="hidden" wire:model.lazy="address_longitude" id="address-longitude" value="0" />
<!-- End in Seach google maps -->
This is my javascript code.
<script>
function initialize() {
$('form').on('keyup keypress', function(e) {
var keyCode = e.keyCode || e.which;
if (keyCode === 13) {
e.preventDefault();
return false;
}
});
const locationInputs = document.getElementsByClassName("map-input");
const autocompletes = [];
const geocoder = new google.maps.Geocoder;
for (let i = 0; i < locationInputs.length; i++) {
const input = locationInputs[i];
const fieldKey = input.id.replace("-input", "");
const isEdit = document.getElementById(fieldKey + "-latitude").value != '' && document.getElementById(fieldKey + "-longitude").value != '';
const latitude = parseFloat(document.getElementById(fieldKey + "-latitude").value) || -6.251855;
const longitude = parseFloat(document.getElementById(fieldKey + "-longitude").value) || 106.978942;
const map = new google.maps.Map(document.getElementById(fieldKey + '-map'), {
center: {lat: latitude, lng: longitude},
zoom: 15
});
const marker = new google.maps.Marker({
map: map,
position: {lat: latitude, lng: longitude},
});
marker.setVisible(isEdit);
const autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.key = fieldKey;
autocompletes.push({input: input, map: map, marker: marker, autocomplete: autocomplete});
}
for (let i = 0; i < autocompletes.length; i++) {
const input = autocompletes[i].input;
const autocomplete = autocompletes[i].autocomplete;
const map = autocompletes[i].map;
const marker = autocompletes[i].marker;
google.maps.event.addListener(autocomplete, 'place_changed', function () {
marker.setVisible(false);
const place = autocomplete.getPlace();
geocoder.geocode({'placeId': place.place_id}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
const lat = results[0].geometry.location.lat();
const lng = results[0].geometry.location.lng();
setLocationCoordinates(autocomplete.key, lat, lng);
}
});
if (!place.geometry) {
window.alert("No details available for input: '" + place.name + "'");
input.value = "";
return;
}
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
marker.setPosition(place.geometry.location);
marker.setVisible(true);
});
}
}
function setLocationCoordinates(key, lat, lng) {
const latitudeField = document.getElementById(key + "-" + "latitude");
const longitudeField = document.getElementById(key + "-" + "longitude");
latitudeField.value = lat;
longitudeField.value = lng;
Livewire.emit('lat')
}
And this is my livewire controller
// Form properties
public $currentPage = 1;
public $property_name;
public $address_address;
public $postal_code;
public $property_phone_number;
public $number_of_rooms;
public $pages = [
1 => [
'heading' => 'General Information',
'subheading' => 'Enter',
],
2 => [
'heading' => 'Property Detail',
'subheading' => 'Enter',
],
];
private $validationRules = [
1 => [
'property_name' => ['required', 'min:3'],
'address_address' => ['required', 'min:3'],
'postal_code' => ['required', 'min:3'],
'property_phone_number' => ['required', 'min:3'],
'number_of_rooms' => ['required'],
],
2 => [
'password' => ['required', 'string', 'min:8'],
'confirmPassword' => ['required', 'string', 'same:password', 'min:8'],
],
];
public function updated($propertyName)
{
$this->validateOnly($propertyName, $this->validationRules[$this->currentPage]);
}
public function goToNextPage()
{
$this->currentPage++;
}
public function goToPreviousPage()
{
$this->currentPage--;
}
Can someone help me how to emit the google maps API and listen to it in JavaScript, therefore, google maps will always be rendered? Thanks
postman.response.txt
https://gist.github.com/stanislavgr79/e82999e5ae69876f0316280687388a25
var app = new Vue({
el: "#app3",
data: {
path: "",
sortEvent: "",
eventsValue: [],
},
methods: {
getResponse(){
this.requestByParam(this.sortEvent);
},
requestByParam: function (byParam) {
this.$http
.get(this.path, {
params: { sortEvent: this.sortEvent },
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then((response) =>
response.json().then((data) => {
let listResultQuery = [];
if (data.length == 0) {
return;
}
// data.forEach((element) => {
// listResultQuery.push(element);
// dont work
});
this.eventsValue = data;
this.emptyMessage = "";
})
);
},
},
});
<div id="app3">
<events_nav path=${resource.path}></events_nav>
<all_events id="all-events" :eventsValue="eventsValue"></all_events>
</div>
i try reformat:
$.ajax({
type: method_event,
url: path_event + '.sort.json',
data: params,
contentType: 'application/json',
success: function (response, status, request) {
if (status == 'success') {
var output = "";
$.each(response, function (key, value) {
output += "<div class='span3'>";
output += "<h3>" + key + "<i class='events__" + key + "'></i></h3>";
$(value).each(function (index, el) {
output += "<ul class='icons icons_type'><i class='icon-" + el.topic + "'></i>";
output += "<li class='events_type'>";
output += "<span class='date' type='date'>" + formatDate(el.eventStartDate) + "</span>";
output += "<h4><a href='"+el.titleLink+"' rel='"+el.typeOfOpen+"'>" + el.title + "</a></h4>";
output += el.description;
output += "</li></ul>";
});
output += "</div>";
$('#all-events').html(output);
});
}
}
})
}
now i have error :
Vue.component("all_events", {
props: {
eventsValue: Array,
},
template:
'<div class="span3" v-for="(value, name) in eventList">' +
'<h3>{{ name }}<i class="events__{{ name }}"></i></h3>' +
'</div>',
});
eventsValue - its Object ????? its Array ???????
what i need to write tempalate to see key
$.each(response, function (key, value) {
output += "<div class='span3'>";
output += "<h3>" + key + "<i class='events__" + key + "'></i></h3>";
this method dont work:
<ul id="example-1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
and this dont work:
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
and this dont work:
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
and this dont work:
<div v-for="(value, name) in object">
{{ name }}: {{ value }}
</div>
and this dont work:
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
For the error "Cannot use v-for on stateful component root element because it renders multiple elements"
You just need to wrap the template in another dom element
example:
Vue.component("all_events", {
props: {
eventsValue: Array,
},
template:`
<div>
<div class="span3" v-for="(value, name) in eventList">
<h3>{{ name }}<i class="events__{{ name }}"></i></h3>
</div>
</div>
`});
try that with the code before you reformatted.
this code works. thanks community and Daniel
Vue.component("events_nav", {
props: {
dataPath: String,
},
data() {
return {
sortEvent: "topic",
topic: true,
type: false
};
},
methods: {
requestTopic: function () {
this.sortEvent = "topic";
this.$root.sortEvent = this.sortEvent;
this.topic = true;
this.type = false;
this.$root.getResponse();
},
requestType: function () {
this.sortEvent = "type";
this.$root.sortEvent = this.sortEvent;
this.topic = false;
this.type = true;
this.$root.getResponse();
},
},
created: function () {
let servletSelector = ".sort";
let servletExtension = ".json";
this.$root.dataPath = this.dataPath.concat(
servletSelector,
servletExtension
);
this.$root.sortEvent = this.sortEvent;
this.$root.getResponse();
},
template:
'<div class="navbar events_nav">' +
'<div class="navbar-inner">' +
'<span class="brand">View By:</span>' +
'<ul class="nav" id="event_sort" data-sort="topic" data-method="GET" :data-path="dataPath">' +
'<li :class="{active: topic}" id="events__view-topic"><span #click="requestTopic">Topic</span></li>' +
'<li :class="{active: type}" id="events__view-type"><span #click="requestType">Type</span></li>' +
'</ul>' +
'</div>' +
'</div>',
});
Vue.component("all-events", {
props: {
eventsValue: "",
},
template:
'<div class="row event-listing">' +
'<div class="span3" v-for="(value, name) in eventsValue">' +
'<h3>{{ name }}<event-icon :icon="name"></event-icon></h3>' +
'<event-column :value="value"></event-column>' +
'</div>' +
'</div>',
});
Vue.component("event-icon", {
props: {
icon: String,
},
computed: {
classIcon: function () {
let icon = '';
if (this.$props.icon == 'Database') {
icon = 'icon-hdd'
}
if (this.$props.icon == 'Cloud') {
icon = 'icon-cloud'
}
if (this.$props.icon == 'Mobile') {
icon = 'icon-mobile-phone'
}
if (this.$props.icon == 'Other Topics') {
icon = 'icon-calendar'
}
return icon;
}
},
template:
'<i :class="classIcon"></i>',
});
Vue.component("event-column", {
props: {
value: Array,
},
template:
'<ul class="unstyled" >' +
'<li class="event-list" v-for="item in this.$props.value">' +
'<element-event :element="item"></element-event>' +
'</li>' +
'</ul>',
});
Vue.component("element-event", {
props: {
element: Object,
},
data() {
return {
description: "",
eventdate: ""
};
},
computed: {
classIcon: function () {
let icon = '';
if (this.$props.element.topic == 'Database') {
icon = 'icon-hdd'
}
if (this.$props.element.topic == 'Cloud') {
icon = 'icon-cloud'
}
if (this.$props.element.topic == 'Mobile') {
icon = 'icon-mobile-phone'
}
if (this.$props.element.topic == 'Other Topics') {
icon = 'icon-calendar'
}
return icon;
},
selectTopic: function () {
let result = false;
if (this.$root.sortEvent == "type") {
result = true;
}
return result;
}
},
methods: {
formatDate() {
return new Date(this.$props.element.eventStartDate).toLocaleString('en-US', {
day: '2-digit',
month: 'long'
});
},
},
template:
'<div>' +
'<i v-if="selectTopic" class="icon" v-bind:class="classIcon"></i>' +
'<span class="date" type="date" v-html="formatDate()"></span>' +
'<h4><a :href="element.titleLink" :rel="element.typeOfOpen" v-html="element.title"></a></h4>' +
'<p class="event-description" v-html="element.description"></p>' +
'</div>',
})
var app = new Vue({
el: "#eventviewer-v2",
data: {
dataPath: "",
sortEvent: "",
events: "",
},
methods: {
getResponse() {
this.requestByParam(this.sortEvent);
},
requestByParam: function (byParam) {
this.$http
.get(this.dataPath, {
params: { sortEvent: this.sortEvent },
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then((response) =>
response.json().then((data) => {
this.events = data;
this.emptyMessage = "";
})
);
},
},
});
To remove wrap element...
mounted () {
this.$el.replaceWith(...this.$el.childNodes)
}
I use vue make single page , I want each grid item`s v-link path diffrent.
Now it's like this:
<div v-link="'/detail/' + 'work'" class="itemImg">
I want like this:
<div v-link="'/detail/' + data.title " class="itemImg">
the v-link`s data.title can not find, but data.title in v-for other pace work fine.
her is my code
var png = ".png"
var jpg = ".jpg"
var HtmlFormat = ".html"
// WORK
var db = new loki('workDB.json');
var workCol = db.addCollection('workCol');
var workNames = ["x50", "glmg", "ring", "iwatch", "moto", "edge", "i8", "nike", "shave", "house"];
var workWebglFolder = "assets/webgl/";
var workHtmlFolder = "pages/work/";
var workImgFolder = "img/workImg/";
var workImgkUrls = [];
var workHtmlUrls = [];
var workTitles = [];
var workSummary = [];
$.each(workNames, function(index, title) {
var workWebglUrl = workWebglFolder + title;
var workHtmlUrl = workHtmlFolder + title + HtmlFormat;
var workimgkUrl = workImgFolder + title + png;
var workOBJ = {};
workOBJ.id = index;
workOBJ.useClass = title;
workOBJ.title = title;
workOBJ.link3d = workWebglUrl;
workOBJ.link = workHtmlUrl;
workOBJ.image = workimgkUrl;
workCol.insert(workOBJ);
var useClass = "." + title;
workHtmlUrls.push(workHtmlUrl);
workImgkUrls.push(workimgkUrl);
$.ajax({
url: workHtmlUrl,
async: false,
success: function(data) {
title = $(data).filter('title').text();
summary = $(data).filter(useClass).text();
workOBJ.title = title;
workOBJ.summary = summary;
}
});
})
// BLOG
var db = new loki('blogDB.json');
var blogCol = db.addCollection('blogCol');
var blogNames = ["waveLoader", "playcanvas-introduce", "lokiJS", ];
var blogHtmlFolder = "pages/blog/";
var blogImgFolder = "img/blogImg/";
var blogImgkUrls = [];
var blogHtmlUrls = [];
var blogTitles = [];
var blogSummary = [];
$.each(blogNames, function(index, title) {
var blogHtmlUrl = blogHtmlFolder + title + HtmlFormat;
var blogimgkUrl = blogImgFolder + title + jpg;
BJ.useClass = title;
blogOBJ.title = title;
blogOBJ.link = blogHtmlUrl;
blogOBJ.image = blogimgkUrl;
blogCol.insert(blogOBJ);
var useClass = "." + title;
blogHtmlUrls.push(blogHtmlUrl);
blogImgkUrls.push(blogimgkUrl);
$.ajax({
url: blogHtmlUrl,
async: false,
success: function(data) {
title = $(data).filter('title').text();
summary = $(data).find('.summary').text().substring(0,200) + "...";
blogOBJ.title = title;
blogOBJ.summary = summary;
}
});
})
// db.saveDatabase(function () {
// console.log("save db")
// });
var workdv = workCol.addDynamicView('workCol_view');
workdv.applyWhere(function customFilter(obj){
return obj.id > -1;
});
workdv.applySimpleSort('id')
var blogdv = blogCol.addDynamicView('blogCol_view');
blogdv.applyWhere(function customFilter(obj){
return obj.id > -1;
});
blogdv.applySimpleSort('id')
//USE VUE GET LOKIJS DATA
var lookVue = new Vue({
el: '.pages',
data: {
work: workdv.data(),
blog: blogdv.data()
},
});
console.log(lookVue.work[0].title)
var notFound = Vue.extend({
template: '<h1>Not Found</h1>' +
'<router-view></router-view>'
})
var workComponent = Vue.extend({
template:
'<h1>Work</h1>' +
'<router-view></router-view>'
})
var blogComponent = Vue.extend({
template:
'<h1>Blog</h1>' +
'<router-view></router-view>'
})
var aboutComponent = Vue.extend({
template:
'<h1> aboutComponent </h1>' +
'<a v-link="{ path: \'/subroute\' }" class="btn btn-lg btn-primary" role="button">View SubRoute</a>' +
'<router-view></router-view>'
})
var contactComponent = Vue.extend({
template:
'<h1> 联系 </h1>' +
'<router-view></router-view>'
})
var detail = Vue.extend({
template:
'<h1>Navbar example</h1>' +
'<p>This example is a quick exercise to illustrate how the default, static and fixed to top navbar work. It includes the responsive CSS and HTML, so it also adapts to your viewport and device.</p>' +
'<p>To see the difference between static and fixed top navbars, just scroll.</p>'
})
Vue.config.debug = true;
Vue.use(VueRouter)
var router = new VueRouter({
history: false,
hashbang:true,
// saveScrollPosition:true,
root: '/'
})
Vue.component('newtemp', {
template: '#workVUE',
route: {
data: function(transition) {
transition.next({
// saving the id which is passed in url to $data
itemName: transition.to.params.itemName
});
}
},
data: function() {
return {
itemName:itemName,
}
},
})
router.map({
// '*': {
// component: notFound
// },
'/': {
component: workComponent,
subRoutes: {
'/detail': {
component: detail
}
}
},
'/work': {
component: workComponent,
subRoutes: {
'/detail': {
component: detail
}
}
},
'/blog': {
component: blogComponent,
subRoutes: {
'/detail': {
component: detail
}
}
},
'/about': {
component: aboutComponent,
subRoutes: {
'/detail': {
component: detail
}
}
},
'/contact': {
component: contactComponent
},
'/detail/:itemName': {
name: 'detail', // 给这条路径加上一个名字
component: Vue.component('newtemp')
},
});
var App = Vue.extend()
router.start(App, 'body')
<template v-for="data in work" id="workVUE">
<div class="item scrollItem">
<div v-link="'/detail/' + 'work'" class="itemImg">
<div class="gridImg workImg">
<img v-bind:src="data.image" />
</div>
</div>
<div class="itemTitle">
<h3>{{data.title}}</h3>
</div>
<div class="itemTag">
<div class="tagTitle">
<ul class="tagName">
<li class="tagTip"><h3> 标签: </h3> </li>
<li><h3 class="pageName"> {{data.useClass}} </h3> </li>
<li><h3> {{data.tag}} </h3> </li>
</ul>
<div class="titlePos"> <h3>titlePos</h3> </div>
</div>
</div>
<ul class="info">
<li class="infoItem infoTitle">
<h3>{{data.title}}</h3>
</li>
<li class="infoItem infoCont">
<h3>{{data.date}}</h3>
<h3>作者:laishi</h3>
</li>
</ul>
<ul class="bar">
<li class="barItem barMark">
<div> <i class="fa fa-bookmark" aria-hidden="true"></i> </div>
</li>
<li class="barItem">
<dir> <a class="moreLink" v-bind:href="data.link3d"> <h3> 3D </h3> </a> </dir>
</li>
<li class="barItem barInfo">
<div>
<i class="fa fa-info"></i>
</div>
</li>
</ul>
</div>{{ }}
</template>
Due to the lack of knowledge of the route, the results are often not the same as I think, so please help.
plz fix my code ,thanks+++
With Vue2 you can use in combination with attribute binding (:to)
<li v-for="project in projects">
<router-link :to="'/project/' + project.id">{{project.name}}</router-link>
</li>
I am using App Builder from Telerik with Kendo UI trying to build a SPA application. I am very new to using Telerik and Kendo UI, please forgive the code.
There are two things I am trying to accomplish.
Enable swipe to open and hide the login head image until the user is logged in.
When a user is logged out return to the login screen and disable swipe to open and hide the login header image.
I have tried adding: data-swipe-to-open="false" in the layout, using the .hide on the header in the layout. When I use data-swipe-to-open="false" the #appDrawer does not open (which is what I want) but I cannot set the data-swipe-to-open = true. I cannot find any documentation from Telerik.
Any and all feedback is appreciated.
Login screen as of now
Swipe on login
HTML
<!--Login View-->
<div id="tabstrip-login"
data-role="view"
data-title="Login"
data-model="app.loginService.viewModel"
data-before-show="app.loginService.beforeShow"
data-after-show="app.loginService.afterShow">
<div style="background-image:url(/xxxx.png); background-position:top; background-repeat:no-repeat; background-size:contain; background-color:white;">
<div style="min-width:325px; min-height:144px;"></div>
</div>
<div data-bind="visible: isLoggedIn">
<div data-bind="visible : isExpired">
Expired Card info
</div>
<div id="dvCardInfoContainer" class="panel panel-default " style="background-color:white;" data-bind="invisible : isExpired">
<div class="panel panel-body" style="background-image:url(img/xyx.png); background-size:cover; background-position:center; background-color:white; ">
<div style="display:flex; flex-flow: row nowrap; align-content:center; justify-content:center; align-items:center;">
<div class="dvVerticalTextContainerLeftSide"><div id="memberStatusTop" data-bind="text :memberStatus" class="dvVerticalTextLeftSide capText bold"></div></div>
<div class="dvCenterVerticalContainer">
<ul>
<li data-bind="text :attCompanyName"></li>
<li data-bind="text :attAircraftTypes"></li>
<li data-bind="text :attAircraftRegNum"></li>
<li class="bold" data-bind="text :attExpirationDate"></li>
<li data-bind="text :calcDateTillExp"></li>
</ul>
</div>
<div class="dvVerticalContainerRightSide"><div class="dvVerticalTextRightSide capText bold" data-bind="text :memberStatus" id="memberStatusBottom"></div></div>
</div>
<div id="goodStanding" class="text-center capText bold"> TEXT </div>
</div>
</div>
</div>
<form data-bind="events: { keyup: checkEnter }">
<ul data-role="listview" data-style="inset" data-bind="invisible: isLoggedIn">
<li>
<label>
<div>Username</div>
<input type="text" data-bind="value: username" />
</label>
</li>
<li>
<label>
<div>Password</div>
<input type="password" data-bind="value: password" />
</label>
</li>
</ul>
<input id="login" type="submit" data-role="button" data-bind="click: onLogin, invisible: isLoggedIn" value="Login" class="login-button" />
</form>
</div>
Layout
<div data-role="layout" data-id="tabstrip-layout">
<header id="hdr" data-role="header">
<div data-role="navbar" >
<span data-role="view-title"></span>
<a data-role="button" href="#appDrawer" data-rel="drawer" data-align="left" data-icon="details"></a>
</div>
</header>
<!-- application views will be rendered here -->
</div>
<div id="appDrawer" data-role="drawer" data-title="Navigation">
<header data-role="header">
<div data-role="navbar">
<span data-role="view-title"></span>
</div>
</header>
<ul id="navigation-container" data-role="listview">
<li>Membership Card</li>
<li>Card Info</li>
<li><a onclick="app.clearLocalStorage();">Log Out</a> </li>
</ul>
</div>
app.js
(function (global) {
var app = global.app = global.app || {};
app.clearLocalStorage = function () {
localStorage.clear();
app.loginService.viewModel.set("isLoggedIn", false);
}
app.makeUrlAbsolute = function (url) {
var anchorEl = document.createElement("a");
anchorEl.href = url;
return anchorEl.href;
};
document.addEventListener("deviceready", function () {
navigator.splashscreen.hide();
app.changeSkin = function (e) {
var mobileSkin = "";
if (e.sender.element.text() === "Flat") {
e.sender.element.text("Native");
mobileSkin = "flat";
} else {
e.sender.element.text("Flat");
mobileSkin = "";
}
app.application.skin(mobileSkin);
};
var element = document.getElementById('appDrawer');
if (typeof (element) != 'undefined' && element !== null) {
if (window.navigator.msPointerEnabled) {
$('#navigation-container').on('MSPointerDown', 'a', function (event) {
app.keepActiveState($(this));
});
} else {
$('#navigation-container').on('touchstart', 'a', function (event) {
app.keepActiveState($(this));
});
}
}
app.application = new kendo.mobile.Application(document.body, { layout: "tabstrip-layout", skin: 'nova'});
//$("#hdr").hide();
// app.loginService.viewModel.set("isLoggedIn", true);
}, false);
app.removeActiveStatus = function _removeActiveState(item) {
var currentItem = item;
$('#navigation-container li a.active').removeClass('active');
currentItem.addClass('notActive');
}
app.keepActiveState = function _keepActiveState(item) {
var currentItem = item;
$('#navigation-container li a.active').removeClass('active');
currentItem.addClass('active');
};
app.isOnline = function () {
if (!navigator || !navigator.connection) {
return true;
} else {
return navigator.connection.type !== 'none';
}
};
})(window);
Login.js
function loadState() {
var cardData = localStorage.getItem("userAttributeList");
if (cardData) {
var obj = JSON.parse(localStorage.getItem("userAttributeList"));
var companyName = obj[0].attData;
var airCraftTypes = obj[23].attData;
var airCraftRegNum = obj[24].attData;
var memberType = obj[1].attData;
var x = obj[17].attData;//experation date
var daysTillExpire = app.loginService.viewModel.calcDate(x);
var expirationDate = app.loginService.viewModel.formatDate(x);
app.loginService.viewModel.set("attCompanyName", companyName);
app.loginService.viewModel.set("attAircraftTypes", airCraftTypes);
app.loginService.viewModel.set("attAircraftRegNum", airCraftRegNum);
app.loginService.viewModel.set("attExpirationDate", "Expires: " + expirationDate);
app.loginService.viewModel.set("calcDateTillExp", "Days to expiration: " + daysTillExpire);
var strMembershipDecision = "Paid Members";
if (strMembershipDecision == memberType) {
app.loginService.viewModel.set("memberStatus", "Prefered Member");
}
else { app.loginService.viewModel.set("memberStatus", "Trial Member"); }
if (daysTillExpire <= 0) {
app.loginService.viewModel.wipeout();
}
//app.loginService.viewModel.set("data-swipe-to-open", true);
$("#appDrawer").data("kendoMobileDrawer");
}
else { }
}
(function (global) {
var LoginViewModel,
app = global.app = global.app || {};
// default empty credentials
// configure the local-storage adapter
LoginViewModel = kendo.data.ObservableObject.extend({
userDataSoruce: null,
isLoggedIn: false,
isExpired: false,
showExpired: false,
username: "",
password: "",
authUrl: '',
userUrl: '',
groupUrl: '',
token: null,
groupId: "",
orgId: "",
userId: "",
cardData: null,
airCraftTypes: null,
expirationDate: null,
memberGroupStatus: null,
memberType: null,
airCraftRegNum: null,
companyName: null,
daysTillExpire: null,
onLogin: function () {
var that = this,
username = that.get("username").trim(),
password = that.get("password").trim();
if (username === "" || password === "") {
navigator.notification.alert("Both fields are required!",
function () { }, "Login failed", 'OK');
return;
}
this.getAuthToken();
},
onLogout: function () {
var that = this;
that.clearForm();
that.set("isLoggedIn", false);
},
clearForm: function () {
var that = this;
that.set("username", "");
that.set("password", "");
},
checkEnter: function (e) {
var that = this;
if (e.keyCode == 13) {
$(e.target).blur();
that.onLogin();
}
},
checkAuth: function (response) {
var that = this;
if (response) {
that.getCardInfo();
}
else { alert('Not success'); }
},
getAuthToken: function () {
var that = this, dataSource;
var response = false;
dataSource = new jQuery.ajax({
type: "POST",
url: that.authUrl,
contentType: "application/json; charset=utf-8",
dataType: "json",
data: 'apiKey=' + '&username=' + that.username + '&password=' + that.password,
username: that.username,
password: that.password,
success: function (data, status) {
that.token = data.token;
that.groupId = data.groupId;
that.orgId = data.orgId;
that.userId = data.userId;
response = true;
that.checkAuth(response);
localStorage.setItem("usertoken", data.token);
localStorage.setItem("username", that.username);
localStorage.setItem("password", that.password);
localStorage.setItem("groupId", data.groupId);
localStorage.setItem("orgId", data.orgId);
localStorage.setItem("userId", data.userId);
},
error: function (error) {
alert('Error in validing username and password.');
response = false;
that.checkAuth(response);
return false
}
});
},
getCardInfo: function () {
var that = this, datasoruce;
datasoruce = new jQuery.ajax({
type: "GET",
url: '' + that.userId + '/attribute',
contentType: "application/json",
dataType: "json",
headers: { 'Authorization': that.token },
success: function (data, status) {
localStorage.setItem("userAttributeList", JSON.stringify(data.attribute));
that.cardData = JSON.stringify(data.attribute);
that.loadData();
},
error: function (error) {
console.log(JSON.stringify(error));
}
})
},
loadData: function () {
var that = this;
var obj = JSON.parse(that.cardData);
that.companyName = obj[0].attData;
that.airCraftTypes = obj[23].attData;
that.airCraftRegNum = obj[24].attData;
var memberType = obj[1].attData;
var x = obj[17].attData;//experation date
that.daysTillExpire = this.calcDate(x);
that.expirationDate = this.formatDate(x);
that.set("attCompanyName", that.companyName);
that.set("attAircraftTypes", that.airCraftTypes);
that.set("attAircraftRegNum", that.airCraftRegNum);
that.set("attExpirationDate", "Expires: " + that.expirationDate);
that.set("calcDateTillExp", "Days to expiration: " + that.daysTillExpire);
that.set("isLoggedIn", true);
//checking for membership status
var strMembershipDecision = "Paid Members";
if (strMembershipDecision == memberType) {
that.set("memberStatus", "Prefered Member");
}
else { that.set("memberStatus", "Trial Member"); }
if (that.daysTillExpire <= 0) {
this.wipeout();
}
},
checkMembershipStatus: function (memberStatus, numDaysToExp) {
},
wipeout: function () {
var that = this;
that.set("isExpired", true);
that.set("showExpired", true);
},
formatDate: function (expirationDate) {
var date = new Date(); //date of experation
date.setYear(parseInt(expirationDate.substr(0, 4), 10));
date.setMonth(parseInt(expirationDate.substr(4, 2), 10) - 1);
date.setDate(parseInt(expirationDate.substr(6, 2), 10));
date.setHours(parseInt(expirationDate.substr(8, 2), 12)); // 201609290000
date.setMinutes(parseInt(expirationDate.substr(10, 2), 12));
return (date.toLocaleDateString());
},
calcDate: function (expirationDate) {
var date = new Date(); //date of experation
date.setYear(parseInt(expirationDate.substr(0, 4), 10));
date.setMonth(parseInt(expirationDate.substr(4, 2), 10) - 1);
date.setDate(parseInt(expirationDate.substr(6, 2), 10));
date.setHours(parseInt(expirationDate.substr(8, 2), 12)); // 201609290000
date.setMinutes(parseInt(expirationDate.substr(10, 2), 12));
var today = new Date(); //Setting todays date
today.setYear(today.getFullYear());
today.setMonth(today.getMonth());
today.setDate(today.getDate());
var millisecondsPerDay = (1000 * 60 * 60 * 24);
var millsBetween = (date.getTime() - today.getTime());
var numExpDays = Math.floor(millsBetween / millisecondsPerDay);
return (numExpDays);
}
});
app.loginService = {
viewModel: new LoginViewModel(),
afterShow: function () {
},
beforeShow: function () {
loadState();
},
//
// //loadState();
//var x = app.loginService.viewModel.get("companyName")
//alert(x);
// app.loginService.viewModel.isLoggedIn = true;
//logic to determine if user is logged in or not.
onShow: function () {
}
};
})(window);
I created a worked around using this
<a data-role="button" href="#appDrawer" data-rel="drawer" data-align="left" data-icon="details" data-bind="visible: isLoggedIn"></a>