views:

82

answers:

6

Using Mootools, we can inject an element into another element:

$('childID').inject($('parentID'), 'top');

The second parameter allows me to control the location and can either be 'top' or 'bottom' to inject it into a parent object or 'before' or 'after' to inject it as a sibling.

We can also set the HTML of an element from a string:

var foo = "<p>Some text</p>";
$('parentID').set('html', foo);

My problem is that I want to have the same flexibility with strings as I do with elements. I can't, for example, put a string at the top of an element using set() as this overwrites the HTML rather than appending it at a specific location. Similarly, I can't append HTML after or before a sibling element.

Is there a function that will allow me to inject strings in the same way as I inject elements?

A: 

Insert at bottom:

foo.innerHTML = foo.innerHTML + 'string';

Insert at top:

foo.innerHTML = 'string' + foo.innerHTML;
Michael Robinson
A: 

Try this:

var foo = "<p>Some text</p>"
$('parentID').set('html', foo + $('parentID').get('html')); // prepend/top
$('parentID').set('html', $('parentID').get('html') + foo)); // append/bottom
Ryan Kinal
+1  A: 

Best Solution

The inject method will look like this:

inject: function(element, location) {
    var el = Elements.from(this);

    if($type(el) === 'array') var el = el.reverse();

    return el.inject(element, location);
}

Let's break this into parts.

1) Elements.from(this) will take whatever the method is applied to and convert it into elements:

var foo = "<p>Some text</p>";
var el = Elements.from(foo);
//el is equal to a p element. 

var bar = "<div>First div</div><div>Second div</div>";
var el = Elements.from(bar);
//el is equal to an array containing 2 div elements

2) if($type(el) === 'array') checks if el is an array. If it is then it applies .reverse() to el. This is necessary to inject the elements in the correct order. Otherwise they would inject with, for example, the second div first and the first div second. Obviously if el is just a single element, we don't need to change its order.

3) Finally, we just use the original inject method to inject el into the element specified in the element parameter to the location specified in the location parameter. If el is an array of elements, they will all get injected just fine.

To be able to use this function, we have to add it as a method on string objects. To do this you have to use implement():

String.implement({
    inject: function(element, location) {
        var el = Elements.from(this);

        if($type(el) === 'array') var el = el.reverse();

        return el.inject(element, location);
    }
});

This will allow you to use the inject function on any variable containing a string. Make sure you don't put this inside the domready event i.e. Before window.addEvent('domready', function() { ... });

Now the inject function itself will look like this:

var foo = "<p>Some text</p>";
foo.inject($('parentID'), 'top');

This will create the p element and inject it at the top of parentID.

Alternative Solution

If you just wish to use inject with the 'top' and 'bottom' locations, you can use this inject method instead:

inject: function(element, location) {
    var html = element.get('html')

    if(location === 'top') return element.set('html', this + html);
    else if (location === 'bottom') return element.set('html', html + this);
}

This method will get the innerHTML of the element you need to convert and either concatenate the string with that HTML or the HTML with that string, placing the string at the top or the bottom of the element respectively. The element's innerHTML is then set to this value.

The advantage of this method is that as long as the innerHTML of the element isn't too great, this is likely to be faster as we don't need to create new elements which could be time-consuming if the string contains many top-level sibling elements. Obviously if this situation were reversed (few top-level siblings and small innerHTML), the speed advantage would also be reversed (I haven't tested the speed difference so this is just an educated guess and might be negligible).

The disadvantage, however, is that we can't easily use it with the 'after' and 'before' locations.

Rupert
A: 

couple of things you ought to look at that may help.

First off, slick and mootools 1.3 offer a "nicer" new Element constructor which can add and configure elements from pseudo string markup very nicely:

http://www.jsfiddle.net/dimitar/aQvpb/

new Element('div#myId.myClass.myOtherClass[title=Mouseover Title][text=Dimitar Was Here]').injectAfter(document.id("foo"));

new Element("input#someID.someClass1.someClass2[disabled=true]");

second of all, element.injectAfter(previousEl) and element.injectBefore(followingEl) can also be helpful in injecting somewhere after or before a particular node.

totally do NOT append html by rewriting old html or any events the elements have that are not delegated will be gone (new UIDs)

and you can use Slick with older versions of mootools as well although I can't find the gist for that atm, post here if you're interested. the currently nightly is fairly stable but 1.3 release is due shortly.

Dimitar Christoff
A: 

You want to use text nodes.

To append text to an element:

var yourTextNode = element.appendChild(document.createTextNode("some text"))

To prepend text to an element:

var yourTextNode = element.parentNode.insertBefore(document.createTextNode("some text"), element)

To change the value of the text node, you'd do yourTextNode.nodeValue = "new value here".

Eli Grey
A: 

You're looking for appendText. Example similar to the Mootools docs:

http://mootools.net/docs/core/Element/Element#Element:appendText

HTML

<div id="myElement">partner.</div>

JavaScript

$('myElement').appendText('Howdy, ', 'top');

The second (where) argument defaults to 'bottom' but also accepts 'top', 'bottom', 'before' and 'after'.

Resulting HTML

<div id="myElement">Howdy, partner.</div>

Working example:

http://jsfiddle.net/hq5Gr/

shanebo