JQM 1.4.5 : disabling button breaks page rendering - javascript

Going through a steep learning curve, i am currently experimenting various UX 'toys' that i will require to implement an app. One of these is to disable a button and enable it on the fly. Following the instructions of the good book , I wrote a little snippet of code to test it out. Clicking on "Soap" runs a series of chained promises, and toggles the "Soap1" button disabled prop.
My HTML/JS
<div data-role="content">
<a href="#" id="btn_soap1" class="ui-input-btn ui-btn ui-mini ui-btn-inline ui-icon-back "
onclick="getInitialNotifications();">Soap1</a>
<button id="btn_soap" class="ui-btn ui-btn-inline ui-mini ui-icon-bullets "
onclick="getInitialNotifications();">
Soap
</button>
<script>
$("#btn_soap1").button({ // required initialization
disabled:false
});
$("#btn_soap").on("click", function () {
// bubbled from the onClick thingie in the markup
var isDis = $("#btn_soap1").button("option","disabled");
$("#btn_soap1").button("option","disabled",!isDis);
// var but = $("#btn_soap1");
// var className = "ui-state-disabled";
// if(but.hasClass(className)) {
// but.removeClass(className);
// } else {
// but.addClass(className);
// }
});
</script>
</div>
Intended rendering
Broken rendering (all browsers and device sims and devices)
Question : can you see any noob error in the JS that would cause this side-effect. I added (in comments) my work-around, which works as specified, but is seems counter-intuitive.
EDIT: (from Mr. Duc Nguyen's answer). What breaks the rendering is adding the initialization. If it is not there, i get an exception whining that i am calling a function prior to initialization when changing the disabled state.
EDIT AGAIN : discovered JSfiddle, ... a fiddle that reproduces this

Edited: new answer basing on jsFiddle
You have gotten yourself in a very interesting situation, some points below:
jQM has an auto-initaliasation merchanism, if you want to leverage that, you have to follow the rules, or totally disable it and do the initialisation yourself. jQM global config
You have 2 "buttons", but they are actually 1 <a> and 1 <button>, disabling the <a> was never an easy one, have a look here disabling html link
jQM might confuse you that the <a> tag is a button widget, but it is not! It just has the same styling as a button, not a button widget. Button widget is only applying to <button> and appropriate <input> type (it was clearly mentioned in the documents back in 1.2.0's days, I couldn't find it in the 1.4.5 docs)
So, here is how I would do to leverage the jQM auto-initialisation:
Soap1
<button id="btn_soap" data-inline="true">Soap</button>
Notice on the <a>:
The attribute data-role="button" was to tell jQM to mark it up as a button
This classclass="ui-disabled" was to disable it initially.
And how to disable the link <a> on-the-fly. Notice that by just adding a class, it won't work on some specific infamous browsers, referring to the above stackoverflow answer for more information.
var isDis = $("#btn_soap1").hasClass("ui-disabled");
if (!isDis) {
$("#btn_soap1").addClass("ui-disabled");
} else {
$("#btn_soap1").removeClass("ui-disabled");
}
Again, you can only call .button([method]) on a real button!
Have a look on this updated jsFiddle, I have cleaned things up a bit.

Related

classList.toggle does not behave how it should be

Started a project to build a website, so far was going good until this problem.
The problem: " I'm tried to make a dropdown menu to show options for a post(delete and edit). I made the dropdown menu and it works perfectly on my laptop(Mac-book pro, testing on google chrome), my partner on this project works on a windows desktop computer. I sent him the files for him to test, and it does not work, it does not toggle the "active" on the drop down element, we tried on his computer, chrome, fire-fox, even on his cellphone (safari and chrome) and it does not work. The click works, we tested it."
I will let you know what we did for knowing what was wrong if we could find out a solution.
Tests:
Click works, we made an alert when it was clicked so we know that it entered to the function we made
We did the console.log of the element after the toggle function. In this case something "weird" happened, the output was the element with the "active" on the class but the element in the dev-tool does not change.
We made it with vanilla JS, I could have used jQuery, normally I like to test things with JavaScript for then doing the jump to jQuery, but as this problem came no time for it.
Other questions you might have, is that there are going to be multiple posts, so this is the way I found to solve my problem to know in which post does the user click to make the correct dropdown.
If someone can help me to solve this I would appreciate, normally I tried to find the solutions by myself but in this case was not possible, I think it goes out of my hands and my knowledge and I find it odd that works on one computer only.
Thank you!.
I will show you the part of the code in case is needed.
HTML:
<div onclick="settings(event)"class="settings" id="1508795">
<i class="fas fa-cog"></i>
</div>
<div class="settingsdropdown" id="post1508795">
<ul>
<li>Edit</li>
<li>Delete</li>
</ul>
</div>
JS:
function settings(e){
var postid=e.currentTarget.getAttribute('id');
var settingslist = document.getElementById('post' + postid);
settingslist.classList.toggle("active");
}
```
I would change the html from:
<div onclick="settings(event)"class="settings" id="1508795">
to (note the this):
<div onclick="settings(this)"class="settings" id="1508795">
Then adjust the function to be:
function settings(e){
var settingslist = document.getElementById('post' + e.id);
settingslist.classList.toggle("active");
}

Replacing paragraph tag contents with a random word from javascript

When a user enters the page I would like a div to be in the center with a heading, a quote underneath that is randomly picked from a list and a button to enter the site. This is all well and good but I cannot seem to get the button to fade in the main site and fade out the landing div. Here is a jsfiddle to try and help explain things more.
JSFIDDLE
As you will probably be able to tell, I'm not that great with JavaScript or jquery and what I have done so far is from learning bits and pieces and surfing the web through code examples
I do not see why it will not work as I had a play around in jsfiddle with a simplified version of what I want to do and it worked.
Simplified Version
Below code is simplified version (It wouldn't let me post without adding code?)
HTML
<div class="landingDiv">
<h1>LANDING DIV</h1>
<button id="showMain">Enter Site</button>
</div>
<div class="main">
<h1>Main Site</h1>
</div>
JQUERY
$("#showMain").click(function () {
$(".main").fadeIn(1000);
$(".landingDiv").fadeOut(1000);
});
CSS
.main {
display: none;
opactiy: 0;
}
Thanks in advanced.
Steve.
The first jQuery example threw an error:
$ is not defined
meaning jQuery is not defined/included. Which it wasn't. But in the second jsFiddle, you included jQuery.
You'll notice that on the left hand side of jsfiddle, you'll see that under the "Framewords & Extensions" heading that you can include a Framewordk - so, include jQuery!
Here is the updated fiddle with jQuery included: http://jsfiddle.net/6cGHF/1/
As you move forward in your JavaScript development, it is always a good idea to check your browsers developer tools for errors when something unexpected is happening. It always helps you, and when you ask questions on StackOverflow, providing these errors help us! :)
The shortcut for developer tools in Chrome is F12 - you can see a little red circle with an X in it if you have errors - click it for more info. But developer tools are also available in other major browsers (except IE8 and below).
Edit:
Wrap your click() event function in a $(document).ready()
$(document).ready(function() {
$("#showMain").click(function () {
$(".main").fadeIn(1000);
$(".landingDiv").fadeOut(1000);
});
});
What was happening was that your HTML file is read from top to bottom. So it would have reached your click function before the #showMain element had been read. So, jQuery couldn't find it.
The reason this wasn't a problem in jsFiddle was because all the JavaScript code was wrapped in an "onLoad" function (which is, admittedly, a little different to $(document).ready()) but it solved this problem for you by executing your JavaScript after everything had already been loaded. You can see that on the left hand side in the fiddle I linked above, you'll find a dropdown with "onLoad" selected. In it, you can also choose "OnDomready" (which would be equivalent to $(document).ready())
In summary:
DON'T use $(document).ready() in jsFiddle. You don't need it.
DO use $(document).ready() around javascript that relies on the fact that the DOM is ready (ie. "all of your content is visible to your JavaScript").
The problem in your fiddle is you have not added jQuery so when you try and reference it with '$', a javascript error is thrown. Simply add in the reference to a jQuery library and your fiddle works to fade out the button when clicked.
Your problems:
1) Add jQuery library to your fiddle.
2) Remove opacity:0; from .main in your CSS. The display:none; is sufficient.
3) Use this to fade out/in the elements:
$("#showMain").click(function () {
$(".landingDiv").fadeOut(1000, function () {
$(".main").fadeIn(1000);
})
});

Inline Editing But Instance Doesn't Exist

I have my own custom non-jQuery ajax which I use for programming web applications. I recently ran into problems with IE9 using TinyMCE, so am trying to switch to CKeditor
The editable text is being wrapped in a div, like so:
<div id='content'>
<div id='editable' contenteditable='true'>
page of inline text filled with ajax when links throughout the site are clicked
</div>
</div>
When I try to getData on the editable content using the examples in the documentation, I get an error.
I do this:
CKEDITOR.instances.editable.getData();
And get this:
Uncaught TypeError: Cannot call method 'getData' of undefined
So I figure that it doesn't know where the editor is in the dom... I've tried working through all editors to get the editor name, but that doesn't work-- no name appears to be found.
I've tried this:
for(var i in CKEDITOR.instances) {
alert(CKEDITOR.instances[i].name);
}
The alert is just blank-- so there's no name associated with it apparently.
I should also mention, that despite my best efforts, I cannot seem to get the editable text to have a menu appear above it like it does in the Massive Inline Editing Example
Thanks for any assistance you can bring.
Jason Silver
UPDATE:
I'm showing off my lack of knowledge here, but I had never come across "contenteditable='true'" before, so thought that because I was able to type inline, therefore the editor was instantiated somehow... but now I'm wondering if the editor is even being applied to my div.
UPDATE 2:
When the page is loaded and the script is initially called, the div does not exist. The editable div is sent into the DOM using AJAX. #Zee left a comment below that made me wonder if there is some other command that should be called in order to apply the editor to that div, so I created a button in the page with the following onclick as a way to test this approach: (adapted from the ajax example)
var editor,html='';config = {};editor=CKEDITOR.appendTo('editable',config, html );
That gives the following error in Chrome:
> Uncaught TypeError: Cannot call method 'equals' of undefined
> + CKEDITOR.tools.extend.getEditor ckeditor.js:101
> b ckeditor.js:252
> CKEDITOR.appendTo ckeditor.js:257
> onclick www.pediatricjunction.com:410
Am I headed in the right direction? Is there another way to programmatically tell CKEditor to apply the editor to a div?
UPDATE 3:
Thanks to #Reinmar I had something new to try. The most obvious way for me to test to see if this was the solution was to put a button above the content editable div that called CKEDITOR.inlineAll() and inline('editable') respectively:
<input type='button' onclick=\"CKEDITOR.inlineAll();\" value='InlineAll'/>
<input type='button' onclick=\"CKEDITOR.inline('editable');\" value='Inline'/>
<input type='button' onclick=\"var editor = CKEDITOR.inline( document.getElementById( 'editable' ) );\" value='getElementById'/>
This returned the same type of error in Chrome for all three buttons, namely:
Uncaught TypeError: Cannot call method 'equals' of undefined ckeditor.js:101
+ CKEDITOR.tools.extend.getEditor ckeditor.js:101
CKEDITOR.inline ckeditor.js:249
CKEDITOR.inlineAll ckeditor.js:250
onclick
UPDATE 4:
Upon further fiddling, I've tracked down the problem being related to json2007.js, which is a script I use which works with Real Simple History (RSH.js). These scripts have the purpose of tracking ajax history, so as I move forward and back through the browser, the AJAX page views is not lost.
Here's the fiddle page: http://jsfiddle.net/jasonsilver/3CqPv/2/
When you want to initialize inline editor there are two ways:
If element which is editable (has contenteditable attribute) exists when page is loaded CKEditor will automatically initialize an instance for it. Its name will be taken from that element's id or it will be editor<number>. You can find editors initialized automatically on this sample.
If this element is created dynamically, then you need to initialize editor on your own.
E.g. after appending <div id="editor" contenteditable="true">X</div> to the document you should call:
CKEDITOR.inline( 'editor' )
or
CKEDITOR.inlineAll()
See docs and docs.
You can find editor initialized this way on this sample.
The appendTo method has different use. You can initialize themed (not inline) editor inside specified element. This method also accepts data of editor (as 3rd arg), when all other methods (CKEDITOR.inline, CKEDITOR.replace, CKEDITOR.inlineAll) take data from the element they are replacing/using.
Update
I checked that libraries you use together with CKEditor are poorly written and cause errors you mentioned. Remove json2007.js and rsh.js and CKEditor works fine.
OK, so I have tracked down the problem.
The library I was using for tracking Ajax history and remembering commands for the back button, called Real Simple History, was using a script called json2007 which was intrusive and extended native prototypes to the point where things broke.
RSH.js is kind of old, and I wasn't using it to it's full potential anyway, so my final solution was to rewrite the essential code I needed for that, namely, a listener that watched for anchor (hash) changes in the URL, then parsed those changes and resubmitted the ajax command.
var current_hash = window.location.hash;
function check_hash() {
if ( window.location.hash != current_hash ) {
current_hash = window.location.hash;
refreshAjax();
}
}
hashCheck = setInterval( "check_hash()", 50 );
'refreshAjax()' was an existing function anyway, so this is actually a more elegant solution than I was using with Real Simple History.
After stripping out the json2007.js script, everything else just worked, and CKEditor is beautiful.
Thanks so much for your help, #Reinmar... I appreciate your patience and effort.

How can I make a "reverse preventDefault" in jQuery?

In Private Logistics: Privacy-Sensitive Calendar, Todo, and Personal Information Management, data that is entered can be edited with a click, and there is support for either entering a link as <a href="... or entering a URL, which will be linkified.
This works great but it presents a problem when someone clicks on a link. The desired behavior is for the link to open and not to put the snippet of text into edit mode, which is the reverse of the usual pattern implemented by event.preventDefault()' or '...return false;}. (Clicks outside the link on the element should put the containing element in edit mode, same as a container that doesn't happen to have a link.)
How can I reverse the more common pattern using jQuery? My best guess now is to attempt introspection on the event target and see if it is an anchor. But that's just a best guess; I have seen plenty of examples of the pattern that would cancel the link loading another page but performing the added Ajax functionality of putting the container into edit mode; I'm not sure I've seen the reverse of that pattern which would follow the link and not put the container into edit mode.
I also see a way to dodge the matter by having links load in the same page, but that's the sort of solution I'd prefer to only adopt if there are intractable issues with implementation or the like.
Generally, you don't want to clean up your broad strokes, instead, don't make such broad strokes. Use an if statement prior to running e.preventDefault().
Something like:
var preventedLinks = $('a.preventthislink');
$('a').click(function(e){
if ($(this).index(preventedLinks) != -1) {
e.preventDefault();
}
});
you could alternatively just change the class of whatever you are preventing default on:
$(document).ready(function(){
$('.blue').removeClass('blue').addClass('green');
});

Click a button made from div with JavaScript?

In Google+, the button that is used to post a comment is made from a div:
<div role="button" id=":1vq.post" class="d-s-r tk3N6e-e tk3N6e-e-qc" aria-disabled="false" style="-webkit-user-select: none; " tabindex="0">Post comment</div>
I think I can click it with:
document.getElementById(":1vq.post").click();
But it says that the element have no attribute click, and I found that onclick is null. So how could I click the button with JavaScript?
EDIT: After a chat with wong2 who started this question and a lot of failed guesses for what this question is really about (the question is quite poorly written), what they are trying to do is to write a Greasemonkey userscript to make the enter key press the Post Comment button in Google+ streams. Since I don't have an invite into Google+ yet, I can't even see the relevant code so not much I can do. This question is not about putting anything related to Google+ in your own site - it's about trying to use Greasemonkey to modify the behavior of Google's site in your own browser.
Earlier attempts to help:
id=":1vq.post" is not a legal CSS id name. You can't use the ":" character in a selector name. This causes multiple issues because not only is it not a legal character, but it's also a meaningful character in the CSS selector syntax. So, I see that you have two issues.
First, your selector logic is not working. Second, as others have said, you can't just assign to click in this way with plain javascript (e.g. no framework).
If you change your selector logic to work correctly, you can get it to work properly (using jQuery) like this:
<div role="button" id="aPost" class="d-s-r tk3N6e-e tk3N6e-e-qc" aria-disabled="false" style="-webkit-user-select: none; " tabindex="0">Post comment</div>
$("#aPost").click(function() {
alert("I was clicked.");
});
And, you can see it in action in this jsFiddle: http://jsfiddle.net/jfriend00/Yfnc7/. Click Run and then click on the Post Comment.
click() applies only to elements like input and button.
http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-2651361
onclick would appear in 1990 and not at Google. They should be using addEventListener.
Try to set a breakpoint and see what function is called on click. Then call the function directly.
To trigger a click event handler one can use createEvent plus dispatchEvent.
See example: http://jsfiddle.net/DzVg9/
Note, that Google Plus may actually be using mousedown or mouseup events.
Are you sure you are acurately selecting the button with $(":1vq.post")? Perhaps you need to change it to $("#:1vq.post") or something like that (I'm not sure how JQuery handles the : and . characters).

Categories

Resources