I have a problem making my iframe changing dynamically depending on what I hover.
I have the following code made in vue:
<template>
<div>
<div class="row">
<h2> Ad performance </h2>
</div>
<div class="row">
<div class="col-sm-6">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Client</th>
<th scope="col">Ad</th>
<th scope="col">Impressions</th>
</tr>
</thead>
<tbody>
<tr v-for="(ad, name) in adPerformance.slice(0,15)" :key="ad.adID">
<td>{{ad.client}}</td>
<td #mouseover="mouseEnter">{{ad.ad}}</td>
<td>{{ad.impressions}}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm-6">
<h4> Desktop preview </h4>
<iframe src= "!!!Change this dynamically!!!"
v-show="toShowOnHover" #mouseleave="mouseLeave"
width="800" height="700">
</iframe>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
toShowOnHover: false,
};
},
props: ['adPerformance'],
components: {
},
methods: {
mouseEnter: function(){
this.toShowOnHover = !this.toShowOnHover;
},
mouseLeave: function(){
this.toShowOnHover = false;
}
},
created() {
},
};
</script>
On my local host server, I have tons of ad preview urls, that I want to dynamically change the src in the iframe depending on what Ad you hover.
The type of data on my local host look like this:
Can anyone help making a code to getting these previewURL's into the iframe?
Any help is appreciated!
First, bind the src attribute of the iframe to a variable. Then change the mouseover handler so that it can get the previewURL and set the variable you have chosen to this url.
On mouse leaves set the variable to null.
<template>
<div>
<div class="row">
<h2>Ad performance</h2>
</div>
<div class="row">
<div class="col-sm-6">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Client</th>
<th scope="col">Ad</th>
<th scope="col">Impressions</th>
</tr>
</thead>
<tbody>
<tr v-for="(ad) in adPerformance.slice(0,15)" :key="ad.adID">
<td>{{ad.client}}</td>
<td #mouseover="mouseEnter(ad.previewURL)">{{ad.ad}}</td>
<td>{{ad.impressions}}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm-6">
<h4>Desktop preview</h4>
<iframe
:src="iframeURL"
v-show="toShowOnHover"
#mouseleave="mouseLeave"
width="800"
height="700"
></iframe>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
toShowOnHover: false,
iframeURL: null
};
},
props: ["adPerformance"],
components: {},
methods: {
mouseEnter: function(url) {
this.toShowOnHover = true;
this.iframeURL = url;
},
mouseLeave: function() {
this.toShowOnHover = false;
this.iframeURL = null;
}
},
created() {}
};
</script>
I think asking from people to make you your piece of code is not a good way of learning from problems, so I will just explain you what you could do and if you have any question just shoot!!
You can send into the #mouseover the previewURL as #mouseover="() => mouseEnter(ad.previewURL)"
You can create a local variable as previewURL, and in the mouseEnter function you can assign previewUrl with the parameter you are receiving.
So <iframe :src="previewURL" .../>
This previewURL variable is reactive so if you change it the iframe src will change as well.
Related
I'm trying to use this code hosting on Firebase, but it doesn't work. {{Item.name}} appears instead of the value :(
I already tested the same code on Codepen and it worked. Does the firebase accept vue.min.js?
When deploying, the site displays the {{var}} instead of the table value in Google Sheets.
I'm trying to use this code hosting on Firebase, but it doesn't work. {{Item.name}} appears instead of the value :(
I already tested the same code on Codepen and it worked. Does the firebase accept vue.min.js?
When deploying, the site displays the {{var}} instead of the table value in Google Sheets.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script>
var app = new Vue({
el: '#app',
mounted() {
let vm = this
axios
.get(
'https://sheets.googleapis.com/v4/spreadsheets/{sheetsID}/values/A2:C20?key={apiKey}'
)
.then(function (response) {
let specials = response.data.values
for (let index = 0; index < specials.length; index++) {
const element = specials[index]
let mitem = {
name: element[0],
description: element[1],
price: element[2]
}
if (vm.isEven(index)) {
vm.menuItems_L = vm.menuItems_L.concat(mitem)
} else {
vm.menuItems_R = vm.menuItems_R.concat(mitem)
}
}
console.log(response)
})
},
data: {
menuItems_L: [],
menuItems_R: [],
menuStyle: {
background: '#f2f2f2',
color: '#000'
}
},
computed: {},
methods: {
isEven: function (n) {
return n % 2 == 0
}
}
});
</script>
<body>:
<div id="app">
<section id="specialssection" class="specials-container" v-if="menuItems_L" :style="menuStyle">
<div id="special_component" :style="menuStyle">
<div class="specials-table-container">
<table>
<tbody v-for="item in menuItems_L" :key="item.name">
<tr class="nameandprice">
<td>
<span :style="menuStyle">{{item.name}}</span>
</td>
<td>
<span :style="menuStyle">R${{item.price}}</span>
</td>
</tr>
<tr class="description">
<td colspan="2">{{item.description}}</td>
</tr>
</tbody>
</table>
<table>
<tbody v-for="item in menuItems_R" :key="`specialmenu-${item.name}`">
<tr class="nameandprice">
<td>
<span :style="menuStyle">{{item.name}}</span>
</td>
<td>
<span :style="menuStyle">${{item.price}}</span>
</td>
</tr>
<tr class="description">
<td colspan="2">{{item.description}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
It looks like the only thing wrong is the order of the tags.
You just need to run the vue code after the <div id="app"> tag is loaded into the DOM. Here's an example:
<html>
<head>
<!-- Include all CDN scripts here -->
</head>
<body>
<div id="app" >
</div>
<script>
// Needs to be called after the <div id="app"> tag is loaded into the DOM
var app = new Vue({
el: '#app',
...
})
</script>
</body>
</html>
I am trying to create a Custom Element that allows me to collapse itself from a simple click delegate, but it doesn't seem to work.
I have this code in my js file
import {inject, bindable, bindingMode} from 'aurelia-framework';
export class DataGridCustomElement {
#bindable({ defaultBindingMode: bindingMode.oneTime }) columns = [];
#bindable({ defaultBindingMode: bindingMode.oneTime }) items = [];
#bindable() collpased = true;
collapseClick() {
this.collapsed = !this.collpased;
}
}
And here is my HTML file
<template>
<require from='./data-grid.css'></require>
<div class="collapse-arrow" click.delegate="collapseClick()">
<span class="collapse-icon glyphicon ${collapsed ? 'glyphicon-plus' : 'glyphicon-minus'}" aria-hidden="true"></span>
<span>Order Lines</span>
</div>
<div class="collapse-block" css="${collapsed ? 'display:none;' : 'display:block;'}">
<table class="data-grid">
<thead>
<tr>
<td repeat.for="column of columns">
${column.title}
</td>
</tr>
</thead>
<tbody>
<tr repeat.for="item of items">
<td repeat.for="column of columns">
${item[column.propertyName]}
</td>
</tr>
</tbody>
</table>
</div>
</template>
The crazy thing is it just doesn't seem to at all. It shows collapsed as being false from the get go, even though I set it to true in the class.
I am calling it like so
<data-grid columns.bind="invoiceColumns" items.bind="lineData"></data-grid>
Any ideas? Am I missing something about Custom Elements?
Easy solution. You have a typo in this.collapsed = !this.collpased;.
I am getting issues trying to use the follow Meteor Package: dandv:jquery-rateit.
I am using it for a ticket system where each update will have a start rating. But when I have more than 1 comment the second one always return 0 value.
Here is my code:
JS:
Template.rating.events({
'click .rateit': function(e){
var rating = $('#rate').rateit('value');
console.log(rating);
Session.set('UpdateId', this._id);
var UpdateId = this._id;
console.log(UpdateId);
/*Meteor.call('saveRate',rating,UpdateId);*/
return false;
}
});
Template.rating.rendered = function () {
this.$('.rateit').rateit();
}
HTML:
<template name="Update">
{{#each Updates}}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title" align="center">Update</h3>
</div>
<div class="panel-body">
<table class="table">
<tr>
<td width="15%" nowrap align="left">Created By:</td>
<td width="35%" align="left">{{createdBy.username}}</td>
<td width="15%" nowrap align="left">Created At:</td>
<td width="35%" align="left">{{formatDate createdAt}}</td>
<td width="15%" nowrap align="left">Rating:</td>
<td width="35%" align="left">{{> rating}}</td>
</tr>
<tr>
<td colspan="4">{{description}}</td>
</tr>
</table>
</div>
</div>
{{/each}}
</template>
<template name="rating">
<div class="rateit" id="rate"></div>
</template>
Now when I try to rate the second comment is return 0. Screenshot: http://screencast.com/t/ejaTI98X
No matter what star do I select, it always return 0. I think that the error should be probably in the HTML.
I really appreciate all your help on it. If you have any question just let me know.
Have a great day.
You iterate over Updates and I assume there are more than one update. For each update you call the template {{>rateit}} which then renders a div with id=rate, so you will end up with several divs with the same id, so you don't really know which one $('#rate') you are accessing.
In your event handler you also use the global jQuery handler.
I suggest you use the following pattern instead to scope jQuery local to the templates context
Template.rating.events({
'click .rateit': function(e,template){
var rating = template.$('.rateit').rateit('value');
console.log(rating);
Session.set('UpdateId', template.data._id);
var UpdateId = template.data._id;
console.log(UpdateId);
/*Meteor.call('saveRate',rating,UpdateId);*/
return false;
}
});
I have a parent component as follows
<template>
<div class="row">
<mappings mapping-list="{{currentMappings}}"></mappings>
</div>
</template>
<script>
import Mappings from './content/Mappings.vue';
export default {
data () {
return {
currentMappings: Array
}
},
created () {
this.readData();
},
methods: {
readData () {
this.$http.get('data/Books.xml').then((response)=> {
var x2js = new X2JS();
var jsonObj = x2js.xml_str2json( response.body );
this.getMappings(jsonObj.WAStatus);
});
},
getMappings (jsonObj) {
this.currentMappings = jsonObj.WSSMappings;
}
},
components: { Mappings }
};
</script>
and a child "mappings" component as follows
<template>
<div class="col-lg-4">
<div class="hpanel stats">
<div class="panel-body h-200">
<div class="stats-title pull-left">
<h3>Mappings</h3>
</div>
<div class="stats-icon pull-right">
<img src="images/mappings.png" class="browserLogo">
</div>
<div class="m-t-xl">
<table class="table table-striped table-hover">
<tr v-for="mapping in mappingList ">
<td>name - {{$index}}</td>
</tr>
</table>
</div>
</div>
<div class="panel-footer">
Current WSS - SA Mappings
</div>
</div>
</div>
</template>
<script>
export default {
props: {
mappingList:Array
},
created () {
console.log(this.mappingList);
// console.log(this.$parent.mappings);
}
}
</script>
I am unable to pass data from the parent component to the child component. I am trying to use props here. The error that I am getting is
main.js:2756[Vue warn]: Invalid prop: type check failed for prop "mappingList". Expected Array, got String. (found in component: <mappings>)
Update
As per the suggestions made I have updated the parent component as follows
<template>
<div class="row">
<browser-stats></browser-stats>
</div>
<div class="row">
<mappings :mapping-list="currentMappings"></mappings>
</div>
</template>
<script>
import Mappings from './content/Mappings.vue';
export default {
data () {
return {
currentMappings: []
}
},
created () {
this.readData();
},
methods: {
readData () {
this.$http.get('data/WA_Status.xml').then((response)=> {
var x2js = new X2JS();
var jsonObj = x2js.xml_str2json( response.body );
this.getMappings(jsonObj.WAStatus);
});
},
getMappings (jsonObj) {
this.currentMappings = jsonObj.WSSMappings;
console.log(this.currentMappings.length);
console.log(JSON.stringify(this.currentMappings));
}
},
components: { Mappings }
};
</script>
and the child "mappings" component as follows
<template>
<div class="col-lg-4">
<div class="hpanel stats">
<div class="panel-body h-200">
<div class="stats-title pull-left">
<h3>Mappings</h3>
</div>
<div class="stats-icon pull-right">
<img src="images/mappings.png" class="browserLogo">
</div>
<div class="m-t-xl">
<table class="table table-striped table-hover">
<tr v-for="mapping in mappingList ">
<td>{{mapping._name}}</td>
</tr>
</table>
</div>
</div>
<div class="panel-footer">
Current WSS - SA Mappings
</div>
</div>
</div>
</template>
<script>
export default {
props: {
mappingList:[]
}
}
</script>
but I am getting an empty mappingList which means whenever I am doing console.log(this.currentMappings.length); I get undefined..
Can you please let me know what I am doing wrong here ?
Thanks
1) Fist issue
data () {
return {
currentMappings: Array
}
Should be
data () {
return {
currentMappings: []
}
2) Second issue
<mappings mapping-list="{{currentMappings}}"></mappings>
Should be:
<mappings :mapping-list="currentMappings"></mappings>
3) Third issue
created () {
console.log(this.mappingList);
// console.log(this.$parent.mappings);
}
This will return empty array every time. Because mappingList changed via AJAX and it's happed after created() was called. Try to use vue-devtool (chrome plugin) for better debug experience.
UPDATED:
To be able to watch async changes (like made with AJAX) consider to use watch this way:
{
data(){
//..
},
watch:{
'currentMappings'(val){
console.log('currentMappings updated', currentMappings);
}
}
}
Docs are here.
You use string interpolation ({{ }}) to try and pass the data to the prop - but the interpolation will turn the array into a string.
You should use a binding with v-bind
<mappings v-bind:mapping-list="currentMappings"></mappings>
...short form:
<mappings :mapping-list="currentMappings"></mappings>
I am attempting to refactor my backbone views to have all HTML related markup in external templates. Ideally I would like to have the element that the view is attached to in the external template as well. At the moment I have:
The html template
<h3 class="pull-left">Search</h3>
<input id="customer-search-input" class="input-large search-query" placeholder="Cust #, Name, Suburb or Owner" />
<button id="customer-search-show-all" class="btn pull-right">Show All</button>
<span id="update-time" class ="pull-right"></span>
<table id="customer-search-results-table" class="tablesorter tablesorter-dropbox">
<thead>
<tr>
<th>Customer Number</th>
<th>Customer Name</th>
<th>Suburb</th>
<th>Owner</th>
<th>Phone Number</th>
</tr>
</thead>
<tbody id="customer-list-results">
</tbody>
</table>
And the backbone view that consumes the template:
define(['jquery','underscore', 'backbone', 'text!templates/customerSearch.html','text!templates/customerRow.html', 'jquery.tablesorter' ],
function($, _, Backbone, customerSearchTemplate, customerRow) {
// ... Other sub-views
var CustomerSearch = Backbone.View.extend({
id:'customer-search', // would prefer to have these
className: 'well', // in the template
initialize: function(){
this.$el.html(customerSearchTemplate);
this.customerSearchInput = this.$("#customer-search-input");
},
events: {
"click #customer-search-show-all": "showAll",
"keyup #customer-search-input": "search"
},
search: function(){
var filteredCustomers = this.collection.search(this.customerSearchInput.val(), ['id','companyName','suburb','businessContact']);
this.customerSearchResultsView = new CustomerSearchResultsView({collection: filteredCustomers});
this.customerSearchResultsView.render();
},
showAll: function() {
this.customerSearchResultsView = new CustomerSearchResultsView({collection: this.collection});
this.customerSearchResultsView.render();
}
});
return CustomerSearch;
});
Everything works but it would be great to be able to have the id and className as part of a wrapper div in the template. If I add this to the template then it appears correctly when rendered but is wrapped by another div by the backbone view.
I'm trying to decouple everything as much as possible.
Thanks!
Update 17 Oct 2012
Using the view.setElement method
var CustomerSearch = Backbone.View.extend({
template:_.template(customerSearchTemplate),
initialize: function(){
this.setElement(this.template());
},
// ...
});
with template
<div id="customer-search" class="well">
<h3 class="pull-left">Search</h3>
// ...
</div>
appears to work. Just wondering now if there is performance hit. Will report back.
You can wrap your template element within a script tag with an id.
<script id="custom-search" type="text/template">
<h3 class="pull-left">Search</h3>
<input id="customer-search-input" class="input-large search-query" placeholder="Cust #, Name, Suburb or Owner" />
<button id="customer-search-show-all" class="btn pull-right">Show All</button>
<span id="update-time" class ="pull-right"></span>
<table id="customer-search-results-table" class="tablesorter tablesorter-dropbox">
<thead>
<tr>
<th>Customer Number</th>
<th>Customer Name</th>
<th>Suburb</th>
<th>Owner</th>
<th>Phone Number</th>
</tr>
</thead>
<tbody id="customer-list-results">
</tbody>
</table>
</script>
And then, declare the following option in your view:
template : _.template($('#custom-search').html())
You will then be able to call :
this.$el.html(this.template());
in your initialize function. This will load the content of the script tag.
Why not 'wrap' your template in a parent div which includes the id / class (plus any other attribute you'd want to use)
<div id="customer-search" class="well"> ... </div>
and then use setElement to set the div as the View's el-ement.
(Note: I've never used the text plugin. But I see no reason you couldn't go with this method)
Also: more about setElement.