June 20, 2013

Adding div from JSON in jQuery?

Ted’s Question:

I am getting some data from a page in JSON format
JSON:
{
‘name’ : ‘maverick’,
Image : ‘Jason’
}

I now need to take these values and add them to the #main div.

        <div id="main">
        <div class="a"> name: Eithan <img src="img/Eithan.jpg" /> <div>
        <div class="a"> name: Emma <img src="img/Emma.jpg" /> <div>
       </div>

How do I do that in jQuery for the case there are several objects in the JSON?

You can do this by using $.getJSON() function.

$.getJSON("link/to/json", function(data) {
    $.each(data, function(i, item) {
        $('#main').append('<div class="a"> name: ' + item.name + ' <img src="img/' + item.image + '.jpg" /></div>');
    });
});
May 21, 2013

jQuery complete replace DOM of element with another DOM – faster way?

Tomis’s Question:

I’m using jQuery’s AJAX for getting new content from server. Data is loaded in JSON:

$.ajax({
    url: url,
    data: {
        'ajax': '1',
    },
    dataType: 'json',
    success: somefunction
});

For server-side application limitation, I’m not able to setup more JSON variables inside so I have to load everything into content. That is why I have to load result into jQuery, than search and replace some elements on page, like this (used in somefunction):

var somefunction = function(data) {
    var con = $('<div></div>').html(data.content); // just $(data.content) is not working
    $('div#mainContent').html(con.find('div#ajax-content').html());
    ... // same process with three more divs
}

EDIT: Please, note that I have to do same process to replace three divs!

There is more about that, but as example, it’s enough I hope. My question: For some logic way, I expect that loading result into DOM ($(data.content)), parsing to html (con.find('dix#ajax-content').html()) and back to DOM ($('div#mainContent').html()) seems to me like loosing some resources and decreasing the perfomance so I would like to know if there is any faster way to do it and load DOM directly, like:

$('div#mainContent').dom(con.find('div#ajax-content').dom());

I tried to google it but maybe I don’t know what to type in. Also jQuery documentation does not helped me a lot.

Some facts:

  • jQuery 1.9.1
  • jQuery UI 1.10.3 available

Finally, I know that it would be much more better to do something with server-side app to provide more JSON variables, however, I need to write not-so-easy peace of code which is requiring longer time to develop which I don’t have right now. Doing it on client side would be temporary solution for now, however, I don’t want to decrease performace a lot.

Side-question:

is it correct to use find() function in this case or there is any better one?

EDIT 2 (not working parsing string)
I’m expecting this working but it’s not:

content = '<div id="ajax-title">Pečivo běžné, sladké, slané</div>
<div id="ajax-whereami"><a href="/category/4">Chléba a pečivo</a> » Pečivo běžné, sladké, slané</div>';
$(content);

Actually, $(data.content) should work just fine, but you have to keep in mind that the top level elements can only be reached via .filter() instead of .find(). If the elements you wish to target are at least one level deeper than the root you should use .find() though; in the examples below you can replace .filter() with .find() where appropriate.

var $con = $(data.content);
$('div#mainContent')
  .empty()
  .append($con.filter('div#ajax-content'))
  .append($con.filter('div#another-id'))
  .append($con.filter('div#and-another-id'));

You can also combine the selectors together:

  .append($con.filter('div#ajax-content, div#another-id, div#and-another-id'));

Lastly, since identifiers should only appear once inside a document, you can drop the div part:

  .append($con.filter('#ajax-content, #another-id, #and-another-id'));

Update

Okay, it seems that jQuery doesn’t evaluate data.content properly when there are newlines in the wrong places; this should work in all cases:

var wrapper = document.createElement('div');
wrapper.innerHTML = data.content;

var $con = $(wrapper);

No, There aren’t any other way that will speed up the performance.

In order to traverse along the content, the content has to be loaded somewhere. So what you are doing is perfectly valid.

February 27, 2013

using document.getElementById

Question by Codejoy

I am having a heck of a time getting some data from a dom I want.

I have some html here:

 <ul id="userMenu">
      <li class="userGreet devi">I WANT THIS TEXT HERE </li><li> <a href="javascript:void(0)" class="more" title="Menu">Menu</a>
      <ul> ....
            <li class="home">   
            </li>
      </ul>
      ...</li>
 </ul>

I know if I say

var x = document.getElementById('userMenu');  

I can get “something” back (though this is all in a portal so its incredibly difficult to put java script break points into this). So I am not sure how I can go further to get the string "I WANT THIS TEXT HERE " ?

I think I have to walk through childNodes but not sure how or what exactly I am getting back so I can get at that string, also getElementById didn’t work for the class= would that be getElementByClass ?

New to this DOM stuff.

Answer by jfriend00

Using plain javascript and making your code more robust if the order of elements changes a little bit, you could use both the id and the class to get it like this:

var text = document.getElementById('userMenu').getElementsByClassName("userGreet")[0].innerHTML;

or using tag names, it could be done like this:

var text = document.getElementById('userMenu').getElementsByTagName("li")[0].innerHTML;

Answer by Starx

You can scan through like this

var x = document.getElementById('userMenu');  
var xChilds = x.childNodes;
var requiredElement = null;
for(var i = 0; i < xChilds.length; i++) {
   if(xChilds[i].className.indexOf('usergreet devi') !== -1) {
      requiredElement = xChilds[i];
      break;
   }
}

console.log(requireElement);

jQuery On() is not working for $(document)

Question by Jason Biondo

I am currently in the process of integrating the dropkick.js plugin into my app, but I have run into a few snags. When I change backbone views the events do not work properly and the .live() event associated in dropkick.js just flat out doesn’t work at all. Nothing fires. I decided to upgrade this to using the .on() function and got it sort of working (even though it still deletes my url for some reason).

This doesn’t work at all:

$(document).on("click", ".dk_toggle", function() {

This only works somewhat:

$(".content").on("click", ".dk_toggle", function() {

Do you know why document doesn’t work at all?

My backbone $el is $(".content").

Answer by Starx

Instead of document, use body. It basically gives the same behavior.

$('body').on("click", ".dk_toggle", function() {
//....
});
January 20, 2013

how to determine whether string is a valid html4 tagName?

Question by cc young

given a string, ‘div’ or ‘abc’, is there any way to determine whether the string is a valid html4 tagName?

tried using document.createElement(), but it’s happy with anything:

document.createElement('trash')
=> <trash></trash>

cannot use HTML<tag>Element. for example

document.createElement('tbody')
=> HTMLTableSelectorElement

Answer by minitech

The best way is to have a list of all valid HTML4 elements and check that. This will give you the right result for “a valid HTML4 element” 100% of the time. From here:

var html4 = ["A","ABBR","ACRONYM","ADDRESS","APPLET","AREA","B","BASE","BASEFONT","BDO","BIG","BLOCKQUOTE","BODY","BR","BUTTON","CAPTION","CENTER","CITE","CODE","COL","COLGROUP","DD","DEL","DFN","DIR","DIV","DL","DT","EM","FIELDSET","FONT","FORM","FRAME","FRAMESET","H1","H2","H3","H4","H5","H6","HEAD","HR","HTML","I","IFRAME","IMG","INPUT","INS","ISINDEX","KBD","LABEL","LEGEND","LI","LINK","MAP","MENU","META","NOFRAMES","NOSCRIPT","OBJECT","OL","OPTGROUP","OPTION","P","PARAM","PRE","Q","S","SAMP","SCRIPT","SELECT","SMALL","SPAN","STRIKE","STRONG","STYLE","SUB","SUP","TABLE","TBODY","TD","TEXTAREA","TFOOT","TH","THEAD","TITLE","TR","TT","U","UL","VAR"];

var valid = html4.indexOf(name.toUpperCase()) !== -1;

(Or, using an object, as @SLaks suggested.)

If you absolutely don’t want to do that for some reason, or didn’t actually mean HTML4, and aren’t worried about IE8- compatibility, then you can do this:

var valid = !(document.createElement(name) instanceof HTMLUnknownElement);

Answer by Starx

A rather simple technique is to define your own set of valid HTML Elements

Array.prototype.contains = function(k) {
   return (this.indexOf(k) > -1;
}
var ValidTags = ['html', 'head', ....];
//Then compare
if(ValidTags.contains('trash')) {
   //Then its valid
}
April 29, 2012

returning DOM element objects as a string?

Question by Thomas T

I’m not sure how to phrase my question, so I’ll just post my code and explain what I’m trying to do:

function getNewElement(tagName, className, idName, text){
    var newElement = document.createElement(tagName);
    newElement.className = className;
    newElement.id = idName;
    newElement.innerHTML = text;

    return newElement;
}

If I call

getNewElement("div", "meow", "meow1", getNewElement("span","meow", "meow2", "blahblahblah"));

I just get

<div id="meow1" class="meow">[object HTMLSpanElement]</div>

So my question is, how would I write this to return a string with out converting (potentially expensive operation?) or ghetto patching with strings.

Update:
ghetto patch version:

function getNewElement(tagName, className, idName, text){
    return '<' + tagName + ' class=' + className + ' id=' + idName + '>' + text + '</' + tagName + '>';     
}

Achieves the functionality I wanted, but I feel like it’s not that elegant.

Answer by KooiInc

Not sure, but if you want the contents of #meow2 in the new element #meow1, using the statement as you do, this would be a solution:

function getNewElement(tagName, className, idName, contents){
    var newElement = document.createElement(tagName);
    newElement.className = className;
    newElement.id = idName;
    newElement.innerHTML = 
          typeof contents === 'string' ? contents : contents.innerHTML;
    return newElement;
}

now

getNewElement("div", "meow", "meow1", 
              getNewElement("span","meow", "meow2", "blahblahblah"));

would create a new element #meow1, with the content of a newly created element #meow2. Appended somewhere in the document it would look like:

<div class="meow" id="meow1">blahblahblah</div>

Otherwise, if you want #meow2 to be a child of #meow1, this would be a solution:

function getNewElement(tagName, className, idName, contents){
    var newElement = document.createElement(tagName);
    newElement.className = className;
    newElement.id = idName;
    if (typeof contents === 'string'){
      newElement.innerHTML = contents;
    } else {
      newElement.appendChild(contents);
    }
    return newElement;
}

Now if you would do:

document.body.appendChild(
     getNewElement("div", "meow", "meow1", 
                   getNewElement("span","meow", "meow2", "blahblahblah"))
);

this would be the result:

 <div class="meow" id="meow1">
  <span class="meow" id="meow2">blahblahblah</span>
 </div>

Answer by Starx

Change your function to take multiple type in parameter text

function getNewElement(tagName, className, idName, text){
    var newElement = document.createElement(tagName);
    newElement.className = className;
    newElement.id = idName;
    newElement.innerHTML = 
          typeof text === 'string' ? text: text.outerHTML;
    return newElement;
}
April 22, 2012

innerHTML wont change if a changebox changes

Question by John Smith

I have a basic list:

<select id = "opt">
  <option value="a">a</option>
  <option value="b">b</option>
  <option value="c">c</option>
</select>

Now I must change the selected items in JS. Its done, and then I need the content of this select items (.innerHTML).
But sadly, the innerHTML say nothing is selected… how to fix this?

EDIT: here is the code:

for (var count = 0; count < document.getElementById('opt').childNodes[0].options.length; count++)
{
 if (document.getElementById('opt').childNodes[0].options[count].value == 7) { document.getElementById('opt').childNodes[0].options[count].selected = true; break; }
}
var obj = document.getElementById('opt');
alert (obj.innerHTML);

and that alert() just displays the original HTML code

Answer by Starx

You can do this as such

var opt = document.getElementById("opt");
var listLength = opt.options.length;
for(var i =0; i< listLength; i++) {
   if(opt.options[i].selected) {
      opt.options[i].textContent = 'the change HTML';
   }
}

Demo

April 5, 2012

Jquery (input/textarea).val(): how is it adding content without changing the DOM?

Question by Li Haoyi

take a look at the JsFiddle here:

http://jsfiddle.net/ru2Fg/2/

Essentially, it starts with two textareas: one empty, one with stuff inside, and an input type=text. I was under the impression that to put stuff in an input you change it’s value, and to put stuff in a textarea you add the text as a child to the node.

I perform a $(...).val(...) to change their contents. And their contents do change.

However, the DOM looks exactly the same! I’m printing out the 3 elements with console.log(); they seem unchanged. I look at them with chrome’s inspect element: they seem unchanged.

I’ve looked at jQuery val() change DOM, but that question concludes it’s something funny with firebug not refreshing the HTML it displays. In this case, i’m quite sure inspect element displays the current html that exists on the page: i’ve seen the left attribute changing furiously when things are scrolling, for example. I’m also checking it using the console, which tells me the same thing: nothing changed.

My eyes, though, tell me something has changed, as I’m seeing “10, omg, moo” instead of “blank, hello world, 2000”. What’s going on?

EDIT: I posted the wrong jsFiddle. This should be the correct one now

Answer by Kolink

There is a difference between the value attribute and the value property. When you type in the input box, you are changing the property, not the attribute. The attribute stays the same as when the document was loaded. Among other things, this means you can reset an input box to its default value with elem.value = elem.getAttribute('value');.

Similarly, if you have a drop-down <select> with one of the options having the selected attribute set, even if you choose a different option that attribute will still be there even though the selected property is now false.

The same applies to checkboxes and the checked attribute. The same also applies for the disabled attribute, and several other things too.

Answer by Starx

It is in-fact changing the DOM, other ways the 10 woulnd’t have showed up in the text area anyway. The problem is in the firebug itself(at list the old one), I am not sure if it is still available in the new ones.

To verify, you can use the web console of firefox or console of chrome.

April 4, 2012

php DOM removing the tag (not content)

Question by dr.linux

$mystring="This is mystring. <a href='http://www.google.com'>Google.</a>"; 
$dom = new DOMDocument; 
$dom->loadHTML($mystring); 
$xPath = new DOMXPath($dom); 
$nodes = $xPath->query('//a');
if($nodes->item(0)) { 
    $nodes->item(0)->parentNode->removeChild($nodes->item(0)); 
} 
echo $dom->saveHTML();  

I want to get output:

This is mystring. Google.

But i got just:

This is mystring.

Answer by Tim Cooper

Try the following:

if($nodes->item(0)) {
    $node = $nodes->item(0);
    $node->parentNode->replaceChild(new DOMText($node->textContent), $node); 
} 

Answer by Starx

Or, Use simple techniques to do simple things.

Here is an alternative to strip_tags()

preg_replace('#<a.*?>(.*?)</a>#i', '1', $text)
March 22, 2012

How to increase the maximum call stack in Javascript?

Question by shershams

I have an event, which can fire itself. I try to make the code as efficient as possible, but it can hit maximum call stack in some circumstances, which are out of my control. It’s not an infinite stack and it will end at some point, but sometimes it can potentially crashe before it finishes because of the limit.

Will I increase the number of call stack if I set up 2 similar event listeners and split the code? Or what can I do?

UPDATE: It’s on DOM change event (working with Webkit only, so don’t care about other browsers), which can also modify the DOM based on some conditions. I haven’t really hit that limit yet, but theoritically, it potentially can. I’m still optimizing the code to make as less DOM manipulations as possible.

UPDATE 2: I’m including sample (not real) example:

document.addEventListener('DOMSubtreeModified', function(event){

    this.applyPolicy(event);

}, true);

function applyPolicy(event){
    if( typeof event != "undefined" ){
        event.stopPropagation();
        event.stopImmediatePropagation();
    }

    if( !isButtonAllowed ){
        $('button:not(:disabled)').each(function(){

           $(this).attr('disabled', true);

        });
    }
}

This is just a sample code, but even in this case, if you have say 100s of buttons, the call stack will be in 100s too. Note that if you use $('button').attr('disabled', true);, this will cause call stack problem, because jQuery will be trying to modify the DOM infinitely.

Answer by am not i am

While it sounds like you may need to rethink some code, one possibility would be to put a recursive call in a setTimeout at some given interval. This allows you to begin a new call stack.

Take this example…

var i = 0;

function start() {
    ++i;
    var is_thousand = !(i % 1000);

    if (is_thousand)
        console.log(i);

    if (i >= 100000)
        return; // safety halt at 100,000
    else
        start()
}

It just logs to the console at every interval of 1,000. In Chrome it exceeds the stack somewhere in the 30,000 range.

DEMO: http://jsfiddle.net/X44rk/


But if you rework it like this…

var i = 0;

function start() {
    ++i;
    var is_thousand = !(i % 1000);

    if (is_thousand)
        console.log(i);

    if (i >= 100000) // safety halt at 100,000
        return;
    else if (is_thousand)
        setTimeout(start, 0);
    else
        start();
}

Now at every 1,000, the function will be allowed to return and the next call will be made asynchronously, starting a new call stack.

Note that this assumes that function is effectively ended when the recursive call is made.

Also note that I have a condition to stop at 100,000 so we’re not infinite.

DEMO: http://jsfiddle.net/X44rk/1/

Answer by Starx

You can’t, they are browser dependant and quite frankly they have quite a wide range, so no need to worry about that IMO.

...

Please fill the form - I will response as fast as I can!