Magnific-popup: how to get image url from <img src="...">? - magnific-popup

Is it possible to force magnific-popup to get image url from 'src' attribute of img tag? This way there would be no need to wrap img with a tags.
I tried the code below, but it doesn't work. Returned error is 'undefined' url.
<script type="text/javascript">
$(document).ready(function(){
$('div.gallery').magnificPopup({delegate: 'img'.attr('src') , type: 'image', gallery:{enabled:true}
});
});
</script>
Anyways, is there any option to do with 'img' only, without 'a' tags?
Thanks!

<script type="text/javascript">
$(document).ready(function(){
$('div.gallery').magnificPopup({delegate: 'img' , type: 'image', gallery:{enabled:true},
callbacks: {
elementParse: function() { this.item.src = this.item.el.attr('src'); }
}
});
});
</script>
elementParse http://dimsemenov.com/plugins/magnific-popup/documentation.html#api

I actually have not worked, and I found how to do .
Now the script when clicking pictures increases and creates a gallery of them .
<script type="text/javascript">
$(document).ready(function() {
$('#text').magnificPopup({
delegate: 'img',
type: 'image',
gallery: {
enabled: true
},
callbacks: {
elementParse: function(qw) {
qw.src = qw.el.attr('src');
}
}
});
});
</script>

With magnificPopup 1.1.0
now you have to do like this if you want it to work.
$(document).ready(function() {
$('.myClass').magnificPopup({
type: 'image',
callbacks: {
elementParse: function(item) {
item.src = item.el.attr('src');
}
}
});
});

The accepted answer didn't work for me, either. I ended up using the data-mfp-src attribute, which overrides the value in the href one (as mentioned here: http://dimsemenov.com/plugins/magnific-popup/documentation.html#content-types).
Instead of adding the attribute manually (duplicating the src of the image), I just copied the src value in data-mfp-src attributes for all images before the magnificPopup call. Something like this:
var popupImages = $('div.withPopups img');
popupImages.each(function(){
$(this).attr('data-mfp-src', $(this).attr('src'));
});
popupImages.magnificPopup({type: 'image'});

Related

How can I add a click event to a class in Vue **without** changing the html? [duplicate]

Is there a way to add a click handler inside a Vue instance without writing on the markup? I'm loading an SVG via ajax, and I'd like to use Vue click events on it.
My Vue file looks like this:
<template>
<div>
<div class="map" v-html="map"></div>
</div>
</template>
<script>
export default{
data : function(){
return {
map : 'Loading'
};
},
methods : {
getMap : function(){
var thisMap = this;
axios.get('/img/world-map.svg').then(function (response) {
thisMap.map = response.data;
thisMap.loading = false;
}).catch(function (error) {
thisMap.loading = false;
console.log(error);
});
},
},
mounted : function(){
console.log('WorldMap mounted');
this.getMap();
}
}
</script>
The issue is that I'm loading a rather large SVG straight into the page. In a perfect world I would just do something like this:
<template>
<div>
<div class="map" >
<svg>
<g #click="groupClicked" class="asia" id="asia" xmlns:svg="http://www.w3.org/2000/svg">
<path stroke="#FFFFFF" d="M715.817,47.266c-4.45,1.25-8.903,2.497-13.357,3.739c-1.074,0.327-8.403,1.757-5.678,3.204
c-1.922,2.104-2.993,1.568-5.547,1.536c-1.547,1.333,0.981,1.22-0.558,2.421c-0.976,0.761-0.946,1.257-2.106,0.827
c-0.368-0.136-2.223-0.261-1.543,0.759c2.082,1.3,0.231,3.046-1.466,4.011c-1.831-0.38-3.271-1.611-5.245-1.293
c-1.229,0.196-2.104,0.763-3.176-0.205c-1.265-1.143,0.371-1.409,1.378-2.177c1.529-1.168,5.473-0.2,2.834-2.668
c1.061-0.979,2.07-0.946,3.206-1.736c-0.297-0.416-0.649-0.773-1.067-1.068c1.047-1.075,1.679-3.036,3.497-2.725
c1.441,0.249,2.046-1.318,3.182-2.137c1.121-0.811,2.4-1.266,3.771-1.402c1.656-0.165,3.271,0.134,4.347-1.427
c0.921-1.334,1.921-1.218,3.468-0.757c1.687,0.504,2.808-0.159,4.442-0.698c2.313-0.118,4.489-0.946,6.812-1.068
c1.043-1.941,2.354-2.07,4.375-2.331c0.653-0.085,6.433-0.678,4.774,1.792C721.041,46.198,718.024,46.605,715.817,47.266
C711.364,48.516,718.356,46.505,715.817,47.266z"/>
</g>
</svg>
</div>
</div>
</template>
However the SVG I'm loading is about 300kb big and I don't want to be carrying that around with all my JavaScript on every page load.
Any comments or solutions welcome.
Edit
Since asking I've actually got quite far with this approach, which isn't perfect but at the moment it seems pretty good.
var vueBus = new Vue({});
$('body').on('click', 'svg g', function(){
var name = $(this).attr('data-name');
vueBus.$emit('svgGroupClicked', name);
});
and then adding a listener in my .vue file
mounted() : function(){
vueBus.$on('svgGroupClicked', function(){ ... });
}
You can just add a click event via plain javascript after the GET request succeeds:
axios.get('/img/world-map.svg').then(function (response) {
thisMap.map = response.data;
thisMap.addClickHandler();
thisMap.loading = false;
})
Your addClickHandler method would look something like this:
methods: {
addClickHandler: function() {
var gEl = this.$el.getElementsByTagName('g')[0];
gEl.addEventListener('click', function() {
alert('I got clicked');
});
},
}
Or, if you're using jQuery:
methods: {
addClickHandler: function() {
$(this.$el).find('g')[0].click(function() {
alert('I got clicked');
});
},
}

How to load external html file in a template in VueJs

I'm new to vue js.
I'm just creating a simple project where I just include vuejs through CDN. not using node/npm or cli.
I keep all my html markup in single html which looks messy as it grows. I tried to split html to views and want to include it by something analogous to ng-include of angularJs
I have worked in angular previously where there is ng-include to load external html files. I'm looking for something similar to that in vue. the whole point is to split my html files into more maintainable separate files.
have come across <template src="./myfile.html"/> but it doesn't work
Can somebody help me out
It's actually remarkably easy, but you need to keep something in mind. Behind the scenes, Vue converts your html template markup to code. That is, each element you see defined as HTML, gets converted to a javascript directive to create an element. The template is a convenience, so the single-file-component (vue file) is not something you'll be able to do without compiling with something like webpack. Instead, you'll need to use some other way of templating. Luckily there are other ways of defining templates that don't require pre-compiling and are useable in this scenario.
1 - string/template literals
example: template: '<div>{{myvar}}</div>'
2 - render function 🤢
example: render(create){create('div')}
Vue has several other ways of creating templates, but they just don't match the criteria.
here is the example for both:
AddItem.js - using render 😠 functions
'use strict';
Vue.component('add-item', {
methods: {
add() {
this.$emit('add', this.value);
this.value = ''
}
},
data () {
return {
value: ''
}
},
render(createElement) {
var self = this
return createElement('div', [
createElement('input', {
attrs: {
type: 'text',
placeholder: 'new Item'
},
// v-model functionality has to be implemented manually
domProps: {
value: self.value
},
on: {
input: function (event) {
self.value = event.target.value
// self.$emit('input', event.target.value)
}
}
}),
createElement('input', {
attrs: {
type: 'submit',
value: 'add'
},
on: {
click: this.add
}
}),
])
}
});
ListItem.js - using template literals (back-ticks)
'use strict';
Vue.component('list-item', {
template: `<div class="checkbox-wrapper" #click="check">
<h1>{{checked ? '☑' : '☐'}} {{ title }}</h1>
</div>`,
props: [
'title',
'checked'
],
methods: {
check() {
this.$emit('change', !this.checked);
}
}
});
and the html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
<script src="ListItem.js"></script>
<script src="AddItem.js"></script>
</head>
<body>
<div id="app">
<add-item #add='list.push({title:arguments[0], checked: false})'></add-item>
<list-item v-for="(l, i) in list" :key="i" :title="l.title" :checked="l.checked" #change="l.checked=arguments[0]"></list-item>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
newTitle: '',
list: [
{ title: 'A', checked: true },
{ title: 'B', checked: true },
{ title: 'C', checked: true }
]
}
});
</script>
</body>
</html>
TL; DR;
See it in action at : https://repl.it/OEMt/9
You cant. You must use async components - read guide here
Actually you can. This is kinda easy. Depends on your needs and situation. However, this code is NOT technically correct, however it will explain to you how it might work, gives you massive freedom and makes your original vue instance smaller.
To make this work, you will need vue router (cdn is ok) and in this case axios or fetch (if you dont care about supporting older browsers).
The only downfall in my opinion is that in content files you will need to add additional call parameter $parent . This will force vue to work.
index
<div id="app">
<router-link v-for="route in this.$router.options.routes" :to="route.path" :key="route.path">{{ route.name }}</router-link>
<section style="margin-top:50px;">
<component :is="magician && { template: magician }" />
</section>
</div>
<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://unpkg.com/axios/dist/axios.min.js"></script>
<script>
const viewer = axios.create({ baseURL: location.origin });
const routes = [
{"name":"Hello","slug":"hello","path":"/lol/index.html"},
{"name":"Page One","slug":"page_one","path":"/lol/page-one.html"},
{"name":"Page Two","slug":"page_two","path":"/lol/page-two.html"}
];
const app = new Vue({
router,
el: '#app',
data: {
magician: null,
},
watch: {
$route (to) {
this.loader(to.path);
}
},
mounted() {
this.loader(this.$router.currentRoute.path);
},
methods: {
viewer(opt) {
return viewer.get(opt);
},
loader(to) {
to == '/lol/index.html' ? to = '/lol/hello.html' : to = to;
this.viewer(to).then((response) => {
this.magician = response.data;
}).catch(error => {
alert(error.response.data.message);
})
},
huehue(i) {
alert(i);
}
}
});
</script>
hello.html content
<button v-on:click="$parent.huehue('this is great')">Button</button>
page-one.html content
<select>
<option v-for="num in 20">{{ num }}</option>
</select>
page-two.html content
// what ever you like
router explanation
To make this work perfectly, you will need to find a correct way to configure your htaccess to render everything if current page after first view is not index. Everything else should work fine.
As you can see, if it is index, it will load hello content file.
I faced the same issue and this is how I solved it , I also made a video about this question https://www.youtube.com/watch?v=J037aiMGGAw
create a js file ,for your component (logic) let's call it "aaaa.vue.js"
create an HTML file for your template that will be injected in your "aaaa.vue.js" and let's call it "aaaa.html"
Component file (Logic file javascript)
const aaaa = {
name:"aaaa",
template: ``,
data() {
return {
foo:"aaaa"
};
},
methods: {
async test() {
alert(this.foo)
},
},
};
Template file (HTML)
<!--template file-->
<div>
<button #click="test" > click me plz </button>
</div>
index.html
<html>
<head>
<title>my app</title>
</head>
<body>
<div id="app" class="main-content col-12">
<aaaa></aaaa>
</div>
</body>
</html>
<script src="axios.min.js"></script>
<script src="vue.js"></script>
<!-- load js file (logic) -->
<script src="aaaa.vue.js"></script>
<script>
document.addEventListener("DOMContentLoaded", async function () {
//register components
let html = await axios.get("aaaa.html"); // <---- Load HTML file
aaaa.template = html.data;
Vue.component("aaaa", aaaa);
new Vue({
el: "#app",
name: "main",
//... etc
});
});
</script>
Update :
I also created an example on github to see it in action
https://github.com/nsssim/Vue-CDN-load-component
Sure you can, this is the way we are doing it in all our components of our app.
<template src="../templates/the_template.html"></template>
<script>
export default {
name: 'ComponentName',
props: {},
computed: {},
methods: {},
};
</script>
<style lang="scss">
#import '../styles/myscss_file';
</style>
Will need to add
runtimeCompiler: true
to your vue.config.js file. That's it.

VueJS + Rest API list rendering issue

I have a Spring Data Rest backend and in src/main/resources/static html + js assets which work fine. My issue is that I can't understand how to render the data picked up from the webservice in the interface.
In case I set the data explicitly as an array, it works fine (see https://v2.vuejs.org/v2/guide/list.html).
Thank you in advance!
...
const ListFormsApi = {
template: '<div><ul><li v-for=\'item in items\'>{{item.details.Title}}</li></ul></div>',
data: function(){
return {
items: ''
}
},
created: function() {
this.get()
},
methods: {
get: function() {
axiosInstance.get('/contactTemplate')
.then(function (response) {
this.items = response.data._embedded.contactTemplate
}).catch(function (error) {
console.log(error)
}
);
}
}
}
...
The webpage is quite simple and straightforward from documentation examples (assume that complete html and head tags are present as well...
<body>
<div id="app">
<h1><router-link to="/">ContactForm Factory!</router-link></h1>
<p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-link to="/listForms">List Forms</router-link>
<router-link to="/listFormsApi">List Forms API</router-link>
</p>
<router-view></router-view>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router#2.0.0/dist/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
I think this is happening because scope of this is not what you are expecting inside the then block of axiosInstance, you need to make following change to make it work.
methods: {
get: function() {
var self = this
axiosInstance.get('/contactTemplate')
.then(function (response) {
self.items = response.data._embedded.contactTemplate
}).catch(function (error) {
console.log(error)
}
);
}
You can have a look at my answer on the similar problem here.
When you are registering the .then() callback the context of the function changes.
In order to keep the context you can use the bind method.
methods: {
get: function() {
axiosInstance.get('/contactTemplate')
.then(function (response) {
this.items = response.data._embedded.contactTemplate
}.bind(this)) // added .bind
.catch(function (error) {
console.log(error)
});
}
}
vue-resource is now using response.body rather than data so look to update as follows:
methods: {
get: function() {
axiosInstance
.get('/contactTemplate')
.then((response) => {
this.$set(this.$data, 'items', response.body._embedded.contactTemplate)
})
.catch((error) => {
console.log(error)
});
}
}
I've also used arrow syntax to correct the scope of this and this.$set to ensure the data that you set is reactive.
If this still doesn't produce the desired result I'd confirm the data is correctly returning from the endpoint. Vue-resource has methods such as response.json() available if for instance the server responds with an incorrect content-type.

Facebook FB sharer with jQuery- "FB is not defined" error

I am implementing facebook share. However I get error Uncaught ReferenceError: FB is not defined. However, if I put code inside getScript function (in code below) then it works, but only at page load.
Viewed lots of answers like this, but was not able to get the solution.
<div id="fb-root"></div>
<script>
jQuery(document).ready(function() {
jQuery.ajaxSetup({ cache: true });
jQuery.getScript('//connect.facebook.net/en_UK/all.js', function(){
window.FB.init({
appId: 'XXX',
});
jQuery('#loginbutton,#feedbutton').removeAttr('disabled');
});
FB.ui(
{
method: 'feed',
name: 'Facebook Dialogs',
link: 'http://XXX.website',
picture: 'http://XXX.website/logoroundTR.gif',
caption: 'MyCaption',
description: 'MyDescription'
},
function(response) {
if (response) {
alert('Post was published.');
} else {
alert('Post was not published.');
}
}
);
});
</script>
<button><fb:like href="http://XXX.website/" layout="button_count" action="like" show_faces="true" share="true"></fb:like></button>
p.s.: Second question: How do I link the button to FB.ui function. Any easy way?
Ok found a workable solution. Slight Hack.
Removed FB.ui and put it in the button onclick and it works great.
So for custom title, caption, image and description for facebook javascript sdk, one can do following:
<div id="fb-root"></div>
<script>
jQuery(document).ready(function() {
jQuery.ajaxSetup({ cache: true });
jQuery.getScript('//connect.facebook.net/en_UK/all.js', function(){
window.FB.init({
appId: 'appID',
});
jQuery('#loginbutton,#feedbutton').removeAttr('disabled');
});
});
</script>
<button onclick="javascript:FB.ui({method: 'feed',name: 'Facebook Dialogs',link: 'http://xxxY.com',picture: 'http://xxxy.com/wp-content/img/logoroundTR.gif',caption: 'SandeepCaption',description: 'SandeepDescription'});"> Click Here </button>

phpstorm javascript autoindent problem

writing a code block with auto indent. no manual tabbing...
$(document).ready(function() {
$("#welc").toggle(function() {
$(this).val("hello");
}, function() {
$(this).val('hell');
});
});
</script>
got a result like that but it should be like:
<script type="text/javascript">
$(document).ready(function() {
$("#welc").toggle(function() {
$(this).val("hello");
}, function() {
$(this).val('hell');
});
});
</script>
a bug or i am missing something?
Please check this issue. Should be addressed in 2.1.1 or next update.