I am using a jQuery plugin that makes the frontend of my website function correctly. Since Ember initializes after the plugin my website doesn't work. The plugin initializes when a secondary configuration script executes. I put this script in a function on the client-side page. The plugin is referenced in the head. The script is in the body inside of Handlebars (at the bottom so Handlebars still works). How would I execute my function after Ember initializes.
EX:
<head>
<script type="text/javascript src="plugin.js"></script>
</head>
<body>
<script type="text/handlebars>
<!--Website-->
<script type="text/javascript">
function initializeMyPlugin(){
// Plugin Configuration
// I believe this needs to be executed after Ember initializes
}
</script>
</script>
<!--Ember File References-->
</body>
The best thing would probably be to wrap your plugin inside a component and execute the function inside didInsertElement
Something like:
App.SomeComponent = Ember.Component.extend({
didInsertElement: function(){
initializeMyPlugin();
}
});
I suggest watching this by Evil Trout to get many more details about wrapping a jQuery plugin in your component
Related
In our project we've previously been using Thymeleaf, but now that we're moving over to Vue.js, we're experiencing some issues using the same ad scripts. The scripts look like this. I've only altered the URLs.
<script data-adfscript="sub.adcompany.net/asdf/?id=256746"></script>
<script src="//sub.adcompany.net/url/to/advertisement/script.js" async="async" defer="defer"></script>
If we put these tags in the <template>, Webpack gives the following message:
Templates should only be responsible for mapping the state to the UI.
Avoid placing tags with side-effects in your templates, such as
, as they will not be parsed.
So I've then been Googling all over to find a similar case. There are some plugins that do this for Google Ads, but they won't work for us. Escaping the script tags <\/script> works in a way, but then the script isn't added to the DOM until after loaded, and so it doesn't run.
Has anyone run into similar issues? If so, what was your solution?
Vue file looks something like this:
<template>
<aside class="sidebar-ad ui-wide">
<script data-adfscript="sub.adcompany.net/asdf/?id=256746"></script>
<script src="//sub.adcompany.net/url/to/advertisement/script.js" async="async" defer="defer"></script>
</aside>
</template>
<script>
export default {
data () {
return {}
}
}
</script>
There is a workaround. Works with style tag too.
<component is="script" src="https://www.example.com/example.js" async></component>
You should not treat Vue templates as a your final HTML, although their syntax is nearly identical and is also HTML-syntax compliant.
Templates are just a UI scaffolds for the data (that is why it is called a data-driven paradigm). They get parsed and transformed into render functions that in the end will produce the final and reactive DOM tree. During this process the <script> tags are indeed ommited cause it is not a place for any logic to happen.
However if you really need to embed any 3rd party script within your component there is a neat way to do this.
First, create container for the script:
<template>
<div id="component-root">
<!-- (...) -->
<div v-el:script-holder></div>
</div>
</template>
Then dynamicly create <script> tag and insert it directly to the DOM tree (using pure Vanilla JS):
<script>
export default {
data () {
return {};
},
ready() {
let scriptEl = document.createElement('script');
scriptEl.setAttribute('src', 'https://cdn.com/somescript.js');
scriptEl.setAttribute('data-some-param', 'paramvalue');
this.$els.scriptHolder.appendChild(scriptEl);
},
}
</script>
The this.$els.scriptHolder returns actual DOM element, calling the appendChild() forces the browser to insert DOM node and run the script just like during ordinary HTML code rendering.
Instead of $els you could also use $el which would return the components root DOM element (in this example the <div id="component-root">) or even the $root.$el which would return the Vue App root DOM element.
Note that this.$els is a Vue 1 feature, which has been replaced with $refs in Vue 2: https://v2.vuejs.org/v2/guide/migration.html#v-el-and-v-ref-replaced
You can try with this package
https://www.npmjs.com/package/vue-script2
I made a vue component to handle script loading within the template tags.
Personally, I use it to load ads in my vuejs apps.
here:
https://github.com/TheDynomike/vue-script-component
I found a way to work around this, not sure how well it works but this the way I did it.
Run the <script> in normal html then go to Dev tools and copy the iframe code made by the script and then paste it into the code as iframe instead of the <script>.
just place your in vue template scripts after your app, in exemple at the end of the body
(function($) {
$('#your-app').find('script').appendTo('body')
<script> your vue script (create app)</script>
})(jQuery);
I offen heard that loading jquery as last element is a good idea because this way a web page loads faster. At the same time I have a script in the header which shows error:
$(document).ready(function () {// Uncaught ReferenceError: $ is not defined
...
}
Should I move jquery loader before the script or I need to change this script some way?
Your concrete issue stems from the fact that you execute statements that use jQuery (i.e. they execute $, which is a function in the jQuery library, also called "the jQuery function" because jQuery is an alias) before it is loaded.
True, it is typically recommended to load scripts last, but that still means the scripts have to be loaded in the correct order, with usually jQuery before your own scripts using jQuery.
If you really want to load your own scripts before jQuery for some reason, you need to defer its execution and have a third helper script to run it, e.g.:
// script.js
(function() {
function myLibraryMainFn() {
$('div').text('simulating work, utilizing jQuery');
}
window.myNamespace = {
run: function() {
myLibraryMainFn()
}
};
}());
<!DOCTYPE html>
<html>
<body>
<div></div>
<script src="script.js"></script>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
// Run your script now:
window.myNamespace.run();
</script>
</body>
</html>
Always refer library file first(in your case jQuery), then use it next..For page load and performance add it before body end tags of your HTML
Using the JS loader head.js I'm having a bit of a hard time distinguishing the subtle differences between head.ready() and head.load().
head.ready('jquery.js', function(){//Do something});
VS
head.load('jquery.js', function(){//Do something});
As far as I understand both seem to load 'jquery.js' and then perform a callback when it is loaded. However, in practice I get some edge cases where head.load doesn't work as expected in Firefox making me think I am not understanding where to use head.load and where to use head.ready.
Reading the API it seems like head.load loads the content, but head.ready is an Event Listener, you can also add a callback to head.load and would work too, but head.load is the only one who can actually load the resources, head.ready not.
EDIT: An example
<html>
<head>
<script src="head.min.js"></script>
<script>
// this loads jquery asyncrounously & in parallel
head.load("jquery.min.js");
</script>
</head>
<body>
<!-- some content-->
<!-- injected via a module or an include -->
<script>
// some function that depends on jquery
head.ready("jquery.min.js", function () {
// this will only be executed once jquery has finished loading
$(".main").hide();
});
</script>
<!-- some content-->
</body>
</html>
I'm looking for the best approach to conditionally load some files based on a specific set of conditions.
I have three CSS files and two javascript files which I'm currently loading like so:
<link href="core.min.css" rel="stylesheet" type="text/css">
<link href="add_regular.min.css" rel="stylesheet" type="text/css">
<link href="add_retina.min.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery-plugin.min.js"></script>
As is evident the fourth file is JQuery and the fifth is my JQuery plugin. Inside the JQuery plugin are a series of functions that are like tests e.g. isMobile, isRetina, isPhone, etc. However, let's focus on isRetina.
What I am trying to accomplish is as follows:
Load JQuery and my JQuery Plugin first
Use isRetina function inside my JQuery plugin to check whether the device has a retina display
Load core.min.css
Load add_regular.min.css if not Retina display, or load add_retina.min.css if Retina display
Currently I'm loading all three CSS files and I wouldn't want to do that because I've got a bunch of other CSS files and I want to load them as my JQuery plugin determines which one is best as per my above example. For example, I might have a phone.min.css that I would want to load after I do another test using my plugin's isPhone function.
I'm considering using YepNope and doing something like this:
<script type="text/javascript" src="yepnope.min.js"></script>
<script>
yepnope([{
load: ['jquery.min.js', 'jquery-plugin.min.js'],
test : $.myplugin.isRetina(),
yep : ['core.min.css', 'add_retina.min.css'],
nope : ['core.min.css', 'add_regular.min.css'],
complete : function(){
//my jquery plugin constructor here
$(selector).myplugin(options);
}
}]);
</script>
However, even if the above approach is the correct one, I am not sure how to implement document.ready, as my plugin's constructor needs to run only when the DOM is ready.
I would like some ideas on how I can pull this off using YepNope or any other solution.
Cheers.
I am not sure how to implement document.ready, as my plugin's constructor needs to run only when the DOM is ready.
There are two relevant events
window.addEventListener('load', function () {
// code runs when document+resources have finished loading
});
and
document.addEventListener('DOMContentLoaded', function () {
// code runs when document has finished parsing, but before resources loaded
});
If you wait for either of these events before importing jQuery, I'm not sure what effect it will have on jQuery's inbuilt $(document).ready / similar.
That said, you do have the option of checking document.readyState === 'complete' before attaching listeners, to see if you should invoke straight away.
I was just going over the JQuery Docs for .ready(), and apparently $(function(){}); is equivalent to $(document).ready(function() {}); (I'm not sure how I'm just discovering this #ScratchingMyHead).
I also saw this being used in a YepNope Tutorial on NetTuts+: http://net.tutsplus.com/tutorials/javascript-ajax/easy-script-loading-with-yepnope-js/.
So I guess my earlier code becoming what you see below should solve the problem:
<script type="text/javascript" src="yepnope.min.js"></script>
<script>
yepnope([{
load: ['jquery.min.js', 'jquery-plugin.min.js', 'core.min.css'],
test : $.myplugin.isRetina(),
yep : 'add_retina.min.css',
nope : 'add_regular.min.css',
complete : function(){
//my jquery plugin constructor added to JQuery DOM Ready Stack
$(function(){
$(selector).myplugin(options);
});
}
}]);
</script>
I will test this out and remove this if it doesn't work.
Not sure if I understand you correctly but this should work.
Include this by default:
<link href="core.min.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery-plugin.min.js"></script>
<script type="text/javascript">
yepnope([{
load: ['jquery.min.js', 'jquery-plugin.min.js'],
test : $.myplugin.isRetina(),
yep : ['core.min.css', 'add_retina.min.css'],
nope : ['core.min.css', 'add_regular.min.css'],
complete : function(){
//my jquery plugin constructor here
$(selector).myplugin(options);
//Remove the mask here.
}
}]);
// Feel free to call ready() here
$(document).ready(function(){
// whatever you want here
});
</script>
Then you can call ready() adding your specific logic according to the output of your tests. This way ready will only fire once the above has loaded and executed.
I'm working with ASP.Net MVC4 wiht view engine Razor. I like put mask date and time in TexBoxFor I installed for nugget jquery.maskedinput-1.3.min.js and add in the view
(document).ready(function () {
$("#FechaDen").mask("99/99/9999");
$("#HoraDen").mask("99:99:99");
});
But I have this error: Uncaught TypeError: Object [object Object] has no method 'mask'
How I can resolve this problem?
You seem to have forgotted to reference the jquery.maskedinput plugin in your page:
<script type="text/javascript" src="#Url.Content("~/scripts/jquery.maskedinput-1.3.min.js")"></script>
Make sure that the path is correct and that the plugin is actually situated in this folder. Use the Network tab of a javascript debugging tool such as FireBug to ensure that there are no 404 errors with your script references.
Also make sure that you have added this script inclusion after jQuery. Be careful because in the ASP.NET MVC 4 Internet Project Template, the ~/Views/Shared/_Layout.cshtml file renders jquery as a bundle at the end of the DOM:
#Scripts.Render("~/bundles/jquery")
#RenderSection("scripts", required: false)
</body>
So if you are putting this reference inside your view make sure that this happens inside the scripts section:
#section scripts {
<script type="text/javascript" src="#Url.Content("~/scripts/jquery.maskedinput-1.3.min.js")"></script>
<script type="text/javascript">
$("#FechaDen").mask("99/99/9999");
$("#HoraDen").mask("99:99:99");
</script>
}
Also notice that since this script is now at the end of the DOM I have gotten rid of the $(document).ready call which is no longer necessary (and which you got wrong in the code you have shown because you forgot to prefix it with a $).