Revealing module pattern with jQuery not working - javascript

I've been playing around with the revealing module patter. I originally started using the Singleton pattern but from reading around the module pattern seems to be the better option.
So i've tested the following:
var test = (function() {
var init = function () {
alert('hello');
};
return {
init: init
};
})();
and this works fine when calling
<script>test.init();</script>
However, i want to use jQuery so i tried:
var test = (function($) {
var init = function () {
$("#samplediv").html('test');
alert('hello');
};
return {
init: init
};
})(jQuery);
but this doesn't work. It does work when using:
<script>$(function() { test.init(); });</script>
How can i get it to work without the added jQuery when calling it?

Usually, anything that touches the DOM needs to done in the $(document).ready(fn) callback. $(fn) is a shortcut for this.
So the reason it doesn't work is because you are searching for DOM elements that don't exist yet. So you have 2 choices. Either you must use the $() wrapper, or find another way to run your code only after the DOM elements exist. Another way to do this is to move your script tag the bottom of the body tag so that the DOM elements can exist when it's ran.
<body>
<!-- your page elements here -->
<script>test.init();</script>
</body>

Related

Which one happens first? WebComponentsReady or dom-change?

I just started on Polymer. There seems to be two events indicating content is ready:
// Listen for template bound event to know when bindings
// have resolved and content has been stamped to the page
app.addEventListener('dom-change', function() {
console.log('Our app is ready to rock!');
});
// See https://github.com/Polymer/polymer/issues/1381
window.addEventListener('WebComponentsReady', function() {
// imports are loaded and elements have been registered
});
I wonder if it is necessary to wrap them together and put the code inside, to make sure that the document is fully loaded before doing any script, for example:
app.addEventListener('dom-change', function() {
window.addEventListener('WebComponentsReady', function() {
// scripts go here
});
});
However, I don't know what is the correct way to do so in all browsers. If WebComponentsReady happens before dom-change, the inside script never execute.
Heck, this might not even be necessary because the polymer-starter-kit doesn't wrap them together. In that case, which types of script should go inside dom-change event and which types of script should go inside WebComponentsReady event?
Use the native ready callback as described here.
<script>
(function() {
Polymer({
is: 'example-element',
properties: {...},
ready: function() {
// access a local DOM element by ID using this.$
this.$.header.textContent = 'Hello!';
}
});
})();
</script>

fake jquery document.ready calls on pages without jquery

I wanted to use some data in another JS script which had a JQuery call $(document).ready(function() inside the block, but i did not want to use JQuery nor init the script, because i just wnat to use some of the predefined variables.
So simply using the script from external source ( as it might get changed ) but skipping the ready() call and just do some data manipulation afterwards.
I got it working with
<script>
var fakeJquery = function(fn) {
this.ready = function () {
return true;
}
};
var $ = function(fn) { return new fakeJquery();}
</script>
But i wonder if there is a better, easier way to do that?

Running JavaScript inside a Handlebars Template

I want to execute a bit of Javascript code inside my handlebars template. Typically in the application I do this
<script type="text/javascript">
var #Model.JavascriptVariableName;
$(function () {
#Model.JavascriptVariableName = new TagInput()
.withAvailableTags(#Html.Raw(Model.AvailableTagsJson))
.withAppliedTags(#Html.Raw(Model.AppliedTagsJson))
.withMinCharsAutocomplete(#Model.MinCharsAutocomplete)
.allowBackspaceDelete(#Model.DeleteWithBackspace.ToString().ToLowerInvariant())
.allowNewTags(#Model.AllowNewTags.ToString().ToLowerInvariant())
.initialize($('##Model.ElementId'), $('##(Model.ElementId)_hidden'));
#if(Model.OnChangeJavascript.IsNotNullOrEmpty()) {
#:#(Model.JavascriptVariableName).onChange = function () { #Html.Raw(Model.OnChangeJavascript) }
}
});
</script>
But since I am already inside of a handlebars template with I tried to just insert the $(function(){}) that just gets spit out as text which makes sense. So how then can I create a bit of dynamic Javascript inside of handlebars???
<script type="text/x-handlebars-template" id="tagsTemplate">
<div>Tags</div>
var #Model.JavascriptVariableName;
$(function () {
#Model.JavascriptVariableName = new TagInput()
.withAvailableTags(#Html.Raw(Model.AvailableTagsJson))
.withAppliedTags(#Html.Raw(Model.AppliedTagsJson))
.withMinCharsAutocomplete(#Model.MinCharsAutocomplete)
.allowBackspaceDelete(#Model.DeleteWithBackspace.ToString().ToLowerInvariant())
.allowNewTags(#Model.AllowNewTags.ToString().ToLowerInvariant())
.initialize($('##Model.ElementId'), $('##(Model.ElementId)_hidden'));
#if (Model.OnChangeJavascript.IsNotNullOrEmpty())
{
#:#(Model.JavascriptVariableName).onChange = function () { #Html.Raw(Model.OnChangeJavascript) }
}
});
</script>
The above code wont work.
Unless you are using handlebar to compile your webpage server side I don't see why you need to wait every time for the window Ready event: $(function(){}) in fact wrap a function to make it sure it will fire only when the DOM is ready (has been loaded).
You can simply skip that part in your code if you want.
I would strongly discourage to put JS code in a template: why don't you generalize that code and compile with Handlebars some DOM stuff with ids or classes that you can use in your "generic" function instead?

Force jQuery to search only in a subtree of a specified element

Is it possible to somehow reconfigure jQuery to search only in a subtree of a specified element?
I need to do something like this:
var lockToSubtree = function (jq) {
//reconfigure jq
return reconfiguredJQuery;
},
myJQuery = lockToSubtree(jQuery, '.my-namespace');
So I have my own instance of jQuery which searches elements only inside '.my-namespace'.
To illustrate my needs here is a sample HTML:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="divOne" class="someClass"></div>
<div class="my-namespace">
<div id="divTwo" class="someClass"></div>
</div>
</body>
</html>
So I can later use in my code:
var $el = myJQuery('.someClass');
And it will search .someClass only in a subtree of a .my-namespace. So it will return only div#divTwo and div#divOne will be skipped because it is not located under a subtree of .my-namespace.
The point is, that I need it to keep searching in a subtree of .my-namespace also when using jQuery functions like .closest() etc., see the final code snippet:
var $myJQuery = lockToSubtree(jQuery, '.my-namespace'),
$el = myJQuery('.someClass'); // $el is the #divTwo element
$el.closest('body'); // finds nothing, because body is not located under .my-namespace
UPDATE:
I agree with #Keith that it is probably not possible to reconfigure jQuery to search in some subtree also with .closest method, which searches upwards. Thus I will be OK with searching in a subtree only when the search direction is down.
I would like to emphasize that I need the jQuery function to have the same functionality like original jQuery (properties like jQuery.fn etc.).
The real life scenario: I need to scope some third party library in our project so it would not affect HTML until some level of depth. The library is a one line of a JavaScript minified code using global jQuery object. All I need is to wrap it in self-invoking function and pass to it some modification of jQuery function which searches only in some subtree of a DOM, but contains all the properties as normal jQuery.
This code maybe explains it better:
(function (jQuery) {
// I am passing jQuery through parameter
// ... here is the library code
}(/* here I want to inject modified jQuery */));
You can create a wrapper function for the jQuery selector like so:
$Q = function (select, opts) {
return $(".my-namespace", opts).find(select);
};
And then just call your wrapper as you would jQuery $Q(".element").children() etc....
jSFiddle here
You can do this with closest to pass a context:
var namespace = $(".my-namespace").get()[0];
$(".foo").closest("p.bar", namespace);
You are asking for something that jQuery does not support, since .closest() will search up the DOM tree all the way to the document. Something terribly expensive, but that will do what you are asking is to clone the .my-namespace into a document fragment. Then, .closest() will not go higher than the document fragment because fragments do not have parents.
I would suggest writing your own .closest() method to make sure you stop where you want, and then use Dormouse's answer for searching down.
I can't accept #Dormouse's or #ArunPJohny's answers because both returns simple functions which do not have another jQuery functions inside like jQuery.fn, so it is impossible to use their solutions.
Here is what I came up after reading #ArunPJohny's code and what works fine for me:
(function (jQuery) {
// third party library using my own modified jQuery function
}((function ($) {
var $wrapper = $('.cms-bootstrap'),
scopedjQuery = function (selector) {
return $(selector, $wrapper);
};
// Copy all jQuery properties into
// scopedjQuery so they can be used later
for (var k in $) {
if ($.hasOwnProperty(k)) {
scopedjQuery[k] = $[k];
}
}
return scopedjQuery;
}(window.jQuery.noConflict()))))

Scope issue inside a custom object

I think I am having a scope visibility issue I can't figure out exactly: when I log the variable displayatonce I get back the right result, but as I try to use the buttons I get nothing in return. I have also tried to log this.navbuttons but all I get is an empty set... I really don't get what's wrong with this code.
<!-- html code -->
<div id="nav">
Previous
Next
</div>
/* Js Script with jQuery */
(function() {
var NewsNavigator = {
init: function(config) {
this.navbuttons = config.navbuttons;
this.displayatonce = config.displayatonce;
this.counter = 0;
this.showNews();
this.enableNav();
},
showNews: function() {
console.log(this.displayatonce);
},
enableNav: function() {
console.log(this.navbuttons);
this.navbuttons.on('click', function() {
console.log("clicked");
});
}
};
NewsNavigator.init({
displayatonce: 3,
navbuttons: $('div#nav').find('a')
});
})();
That is happening because as you are using (function())(); which executes the function immediately, maybe it's running the code before the dom is ready
everything is working fine in the below demo
DEMO
Put all your code inside document ready or at least call the initialize method inside doc ready block like
$(function(){
NewsNavigator.init({
displayatonce: 3,
navbuttons: $('div#nav').find('a')
});
});
Read more about Javascript self executing Anonymous function here
Javascript self executing function "is not a function"
or
http://markdalgleish.com/2011/03/self-executing-anonymous-functions/
You're using jQuery too soon, specifically before the DOM is ready to be searched.
Here is fiddle demonstrating this: http://jsfiddle.net/w7KaY/ (JavaScript is placed in <head>, so init() is invoked pretty early) while here (http://jsfiddle.net/w7KaY/1/), the call to init() is encapsulated in an event handler for jQuery's DOM-ready event.
Make sure the html elements are there in the DOM. I don't see any issue with the script other than the fact you have to use the bind method for binding to events.
this.navbuttons.bind('click', function() {
console.log("clicked");
});

Categories