I have div inside div (nested div) and one button click and one textarea, when i click this button i want output that div in text,and add the text to Textarea
example
<div id="container">
<div class="nested">
<div id="1">
<div class="nested">
<div id="3">helpX</div>
<div id="4">helpY</div>
</div>
</div>
<div id="2">helpZ</div>
</div>
</div>
when i click my button i need the output like this =nested(=nested(helpX)(helpY))(helpZ)
my code is :
$('#BUTTONCLICK').click(function(){
$('#container').find("div").each( function(index) {
....
});
});
I hope you can help me. Thanks .
You have to set up some condition to check whether the child is a nested or child has nested children, or a simple div. So I use a recursive function to handle it:
$('#BUTTONCLICK').click(function(){
var findNest = function(ele) {
// To see if current item needs a nested prefix
var result = $(ele).hasClass("nested") ? '=nested(' : '';
$(ele).find(' > div').each(function(idx, item) {
var $item = $(item);
if ($item.hasClass("nested")) {
// If current cheked item is a nested item, nested it.
result += findNest($item);
} else if ($(item).find(".nested").length > 0) {
result += findNest(item);
} else {
// Current check item is a simple div, add it
result += '(' + $(item).text() + ')';
}
});
// Decide tail
var tail = $(ele).hasClass("nested") ? ')' : '';
return result + tail;
};
var $container = $('#container');
var result = findNest($container);
console.log(result);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="container">
<div class="nested">
<div id="1">
<div class="nested">
<div id="3">helpX</div>
<div id="4">helpY</div>
</div>
</div>
<div id="2">helpZ</div>
</div>
</div>
<div id="BUTTONCLICK">click</div>
If you want to give a level limit, the code can be changed to:
$('#BUTTONCLICK').click(function(){
// Inits
var LEVEL_LIMIT = 2;
var currentLevel = 0;
var findNest = function(ele) {
// Add one level at start.
++currentLevel;
// To see if current item needs a nested prefix
var result = $(ele).hasClass("nested") ? '=nested(' : '';
$(ele).find(' > div').each(function(idx, item) {
var $item = $(item);
var $nestChilds = $(item).find(".nested");
if (currentLevel <= LEVEL_LIMIT &&
($item.hasClass("nested") || $nestChilds.length > 0)) {
// If current cheked item is a nested item, or it has child that is nest, go into it.
result += findNest($item);
} else {
// Current check item is a simple div or level limit reached,
// simply add div texts...(May need other process of text now.)
result += '(' + $(item).text() + ')';
}
});
// Decrease Level by one before return.
--currentLevel;
// Decide tail
var tail = $(ele).hasClass("nested") ? ')' : '';
return result + tail;
};
var $container = $('#container');
var result = findNest($container);
console.log(result);
});
Try
$('#BUTTONCLICK').click(function(){
var text = '';
$('#container').find("div").each( function(index) {
text += $(this).text();
});
$("textarea").val(text);
});
$('#BUTTONCLICK').click(function(){
var findNest = function(ele) {
// To see if current item needs a nested prefix
var result = $(ele).hasClass("nested") ? '=nested(' : '';
$(ele).find(' > div').each(function(idx, item) {
var $item = $(item);
if ($item.hasClass("nested")) {
// If current cheked item is a nested item, nested it.
result += findNest($item);
} else if ($(item).find(".nested").length > 0) {
// For all .nested child from the item, do the findNest action
$(item).find(".nested").each(function(idx, item) {
result += findNest(item);
});
} else {
// Current check item is a simple div, add it
result += '(' + $(item).text() + ')';
}
});
// Decide tail
var tail = $(ele).hasClass("nested") ? ')' : '';
return result + tail;
};
var $container = $('#container');
var result = findNest($container);
console.log(result);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="container">
<div class="nested">
<div id="1">
<div class="nested">
<div id="3">helpX</div>
<div id="4">helpY</div>
</div>
</div>
<div id="2">helpZ</div>
</div>
</div>
<div id="BUTTONCLICK">click</div>
Related
I have some html elements like this:
<div class="items">
<div class="item" data-opt1="val1" data-opt2="val2,val3">Item 1</div>
<div class="item" data-opt1="val4" data-opt2="val2,val5">Item 2</div>
<div class="item" data-opt1="val1" data-opt2="val3,val6">Item 3</div>
<div class="item" data-opt1="val7" data-opt2="val3,val5">Item 4</div>
</div>
and 2 variables to be used as filters, one array of options and one search string like this:
Example 1
var srcString = "val";
var filters = [
'opt1' : ['val1'],
'opt2' : ['val2','val6']
];
In this example item1 and item3 should be visible, item2 and item4 not visible.
Example 2
var srcString = "value";
var filters = [
'opt1' : ['val1'],
'opt2' : ['val2','val6']
];
All items shouldn't be visible, because var srcString contain a word that are not present in any of the data attributes.
Example 3
var srcString = "val6";
var filters = [];
Only item3 should be visible.
Example 4
var srcString = "";
var filters = [
'opt1' : ['val1','val7'],
'opt2' : ['val5']
];
Only item4 should be visible, because item1 and item3 (even if have opt1=val1) not have val5 in opt2.
Example 5
var srcString = "";
var filters = [
'opt1' : ['val1','val7']
];
items: 1,3,4 should be visible.
I was able to make all of these filters work one by one, but problems comes when I try to combinate all of them.
Code for search:
$(".item").each(function(){
var item = $(this);
if (item.data('opt1').toLowerCase().indexOf(srcVal) >= 0
|| item.data('opt2').toLowerCase().indexOf(srcVal) >= 0){
item.removeClass('d-none');
}else{
item.addClass('d-none');
}
});
Code for single filter:
var selectedOptions = filters['opt2'];
$(".item").each(function(){
var item = $(this);
let _options = item.data('opt2') + '';
_options = _options.split(",");
let found = _options.some(r=> selectedOptions.includes(r));
if(found==true){
item.removeClass('d-none');
}else{
item.addClass('d-none');
}
})
Any help is appreciate
Adapting your existing code, you can move the 2nd check inside the pass of the 1st check.
There's a few extra checks needed such as checking that .opt2 exists and has values, but these are simple checks.
$(".item").each(function() {
var item = $(this);
if (item.data('opt1').toLowerCase().indexOf(srcString) >= 0 ||
item.data('opt2').toLowerCase().indexOf(srcString) >= 0) {
item.removeClass('d-none');
var selectedOptions = filters['opt2'];
if (selectedOptions != null) {
let _options = item.data('opt2') + '';
_options = _options.split(",");
if (_options.length > 0) {
let found = _options.some(r => selectedOptions.includes(r));
if (found == true) {
item.removeClass('d-none');
} else {
item.addClass('d-none');
}
}
}
} else {
item.addClass('d-none');
}
});
Fiddle: https://jsfiddle.net/7t26n3pj/
note: this uses OPs code as provided so does not match their examples exactly as missing check for opt1
You can remove the if (_available_) continue to reduce code indentation by moving the check into a separate function and return true/false for pass/not pass - this will also allow you to add new filters going forward.
function applyFilter(filter) {
$(".item").each(function() {
var item = $(this);
if (passesFilter(item, filter))
item.removeClass('d-none');
else
item.addClass('d-none');
})
}
function passesFilter(item, filter) {
if (item.data('opt1').toLowerCase().indexOf(filter.srcString) < 0 &&
item.data('opt2').toLowerCase().indexOf(filter.srcString) < 0)
return false;
var selectedOptions = filter.filters['opt2'];
if (selectedOptions == null) return true;
let _options = item.data('opt2') + '';
_options = _options.split(",");
if (_options.length === 0) return true;
let found = _options.some(r => selectedOptions.includes(r));
return found;
}
// Examples
$("button").click(function() {
var filter = $(this).data("filter");
console.log(filter);
applyFilter(filter);
});
.d-none { display:none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="items">
<div class="item" data-opt1="val1" data-opt2="val2,val3">Item 1</div>
<div class="item" data-opt1="val4" data-opt2="val2,val5">Item 2</div>
<div class="item" data-opt1="val1" data-opt2="val3,val6">Item 3</div>
<div class="item" data-opt1="val7" data-opt2="val3,val5">Item 4</div>
</div>
<button type='button' data-filter='{"srcString":"val","filters":{"opt1":["val1"],"opt2":["val2","val6"]}}'>
test 1
</button>
<button type='button' data-filter='{"srcString":"value","filters":{"opt1":["val1"],"opt2":["val2","val6"]}}'>
test 2
</button>
<button type='button' data-filter='{"srcString":"val6","filters":{}'>
test 3
</button>
<button type='button' data-filter='{"srcString":"","filters":{"opt1":["val1", "val7"],"opt2":["val5"]}}'>
test 4
</button>
<button type='button' data-filter='{"srcString":"","filters":{"opt1":["val1", "val7"]}}'>
test 5
</button>
I'm trying to find and replace URL's for each a element.
Each wrap has data-folder with a path to a file.
Each <a> element inside each wrap links to a file. The problem is that each <a> can be linked with folder up, like '../' or multiple- '../../../'.
I have to check how many '../' each has and for each '../' remove one folder. like '/folder/'
This is my HTML:
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>
And jQuery:
console.clear();
var wrap = $(".wrap");
$.each(wrap, function(index, value) {
var file = $(this).attr("data-folder");
var fileArray = file.split("/");
var links = $(this).find("a");
// loop for link elements (a), it looops 4 times in this case
$.each( links, function( ind, val ){
var $this = $(this);
var aHref = $(this).attr('href');
var hrToArr = aHref.split("/");
console.log(hrToArr);
$.each(hrToArr, function( indx, va ){
if( va == '..' ){
fileArray.pop();
$this.addClass( fileArray );
console.log(va);
}
});
})
});
The results should be:
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>
Codepen here: https://codepen.io/rolandas/pen/XLEXPR?editors=1010
var wrap = $(".wrap");
$.each(wrap, function(index, value) {
var file = $(this).attr("data-folder");
var fileArray = file.split("/").filter(Boolean);
var links = $(this).find("a");
// loop for link elements (a), it looops 4 times in this case
$.each( links, function( ind, val ){
var $this = $(this);
var aHref = $(this).attr('href');
var hrToArr = aHref.split("/").filter(Boolean);
/* console.log(hrToArr) */;
let a = fileArray;
let b = [];
$.each(hrToArr, function( indx, va ){
if(va === '..') {
fileArray.pop();
} else {
b.push(va)
}
});
$this.attr('href', a.concat(b).join('/'));
})
});
Output:
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>
Probably you don't need to remove ../ because servers/browsers usually support finding subdirectory in url (e.g /a/b/../c will be interpret as /a/c). However I do it in below code
let w=[...document.querySelectorAll('.wrap')];
for(let v of w) {
let f = v.dataset.folder.split('/');
for(let a of [...v.children]) {
let n= a.outerHTML.match(/href="(.*)">/)[1].match(/\.\.\//g);
n = n ? n.length : 0;
let p= n==0 ? f : f.slice(0,-n||1);
a.href = p.join('/') + a.pathname.replace(/\.\.\//g,'');
}
}
let w=[...document.querySelectorAll('.wrap')];
for(let v of w) {
let f = v.dataset.folder.split('/');
for(let a of [...v.children]) {
let n= a.outerHTML.match(/href="(.*)">/)[1].match(/\.\.\//g);
n = n ? n.length : 0;
let p= n==0 ? f : f.slice(0,-n||1);
a.href = p.join('/') + a.pathname.replace(/\.\.\//g,'');
}
}
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3">
Link
Link
Link
</div>
<div class="wrap" data-folder="data_folder_1/data_folder_2/data_folder_3/data_folder_4">
Link
</div>
So I will start with my needs. I have a task to create json output using nightwatch.js from the ul list where inside lists are few div elements with classes like name, surname... But really I can't think of any of solutions. Here is my html
<html>
<meta charset="utf-8">
<body>
<ul class="random">
<li class="list">
<div class="name">John</div>
<div class="surname">Lewis</div>
</li>
<li class="list odd">
<div class="name">Nick</div>
<div class="surname">Kyrgios</div>
</li>
</ul>
</body>
</html>
And here is my nightwatch.js script
'Test' : function(browser) {
function iterate(elements) {
elements.value.forEach(function(el) {
browser.elementIdText(el.ELEMENT, function(r) {
browser.elementIdAttribute(el.ELEMENT, 'class', function(att){
// output for json i guess
console.log(att.value + ' => ' + r.value)
})
});
});
}
browser
.url('http://url.com/nightwatch.php')
.waitForElementVisible('body', 8000)
.elements('css selector', 'ul li div', iterate)
.end();
}
Basically this will execute the following:
name => John
surname => Lewis
name => Nick
surname => Kyrgios
Output is a string for both...
And how can I make it like
[{name: "John", surname: "Lewis"}, {name: "Nick", surname: "Kyrgios"}]
This should work. You just need to keep track of the object and place it inside the array after list.
function iterate(elements) {
var objArr = [];
var obj = {};
elements.value.forEach(function(el, idx) {
browser.elementIdText(el.ELEMENT, function(r) {
browser.elementIdAttribute(el.ELEMENT, 'class', function(att){
if (obj.hasOwnProperty(att.value)) {
objArr.push(obj);
obj = {};
}
obj[att.value] = r.value;
});
});
if (idx === (elements.value.length-1)) {
objArr.push(obj);
console.log(objArr);
}
});
}
As with Will's solution, I used straight JavaScript. It does not appear that the nightwatch.js code for this provides any significant benefit. In addition, your question does not specify that only nightwatch.js should be used.
As opposed to Will, I have assumed that the class on your inner <div> elements could be arbitrary and that the arbitrary class should be used as the key/property on the object for that entry. Choosing to use this method vs. restricting it only to a name or surname property will depend on what your HTML really is, and how you want to handle classes which are not those two strings.
var theList = [];
var listItems = document.querySelectorAll('li');
for (var itemIndex=0,itemLength=listItems.length; itemIndex < itemLength; itemIndex++) {
var entry = {};
divs = listItems[itemIndex].querySelectorAll('div');
for (var divsIndex=0, divsLength=divs.length; divsIndex < divsLength; divsIndex++) {
entry[divs[divsIndex].className] = divs[divsIndex].textContent;
}
theList.push(entry);
}
outputJson = JSON.stringify(theList);
console.log(outputJson);
<html>
<meta charset="utf-8">
<body>
<ul class="random">
<li class="list">
<div class="name">John</div>
<div class="surname">Lewis</div>
</li>
<li class="list odd">
<div class="name">Nick</div>
<div class="surname">Kyrgios</div>
</li>
</ul>
</body>
</html>
What about something like this?
function iterate(elements) {
var jsonArray = [];
var jsonBuffer = "";
elements.value.forEach(function(el) {
browser.elementIdText(el.ELEMENT, function(r) {
browser.elementIdAttribute(el.ELEMENT, 'class', function(att){
// output for json i guess
if (att.value == 'name') {
jsonBuffer += "{" + att.value + ":" + "" + r.value + "" + ",";
}
else {
jsonBuffer += att.value + ":" + "" + r.value + "" + "}";
jsonArray.push(jsonBuffer);
jsonBuffer = "";
}
})
});
});
var jsonOutput = "[";
var i = 0;
jsonArray.forEach(function(el) {
if (i < jsonArray.length) {
jsonOutput += el + ",";
} else {
jsonOutput += el + "]";
}
i++;
}
}
I'm not familiar with Nightwatch, but you essentially loop through the elements and push them on to an array.
var results = [];
var entries = document.querySelectorAll('li');
for (var ix = 0; ix < entries.length; ix++) {
var name = entries[ix].querySelector('.name').innerText;
var surname = entries[ix].querySelector('.surname').innerText;
results.push({
name: name,
surname: surname
});
}
console.log(results);
<ul class="random">
<li class="list">
<div class="name">John</div>
<div class="surname">Lewis</div>
</li>
<li class="list odd">
<div class="name">Nick</div>
<div class="surname">Kyrgios</div>
</li>
</ul>
I am doing this by taking the cursor position from the content-editable box. When a new tag is created the cursor comes before the tag but it should be after the tag. Also i am not able to merge/split the tag.
Please give some idea how can i do this.
Visit (https://plnkr.co/edit/DSHKEcOnBXi54KyiMpaT?p=preview) !
What i want here, after pressing the enter key for new tag the cursor should be at the end of tag while it is not and also the merging/spliting functionality like the twitter what's happening box.
Thanks in advance.
Now this code is working fr me
$scope.myIndexValue = "5";
$scope.searchTag = function(term) {
var tagList = [];
angular.forEach($rootScope.tags, function(item) {
if (item.name.toUpperCase().indexOf(term.toUpperCase()) >= 0) {
tagList.push(item);
}
});
$scope.tag = tagList;
return $q.when(tagList);
};
$scope.getTagText = function(item) {
// note item.label is sent when the typedText wasn't found
return '<a>#<i>' + (item.name || item.label) + '</i></a> ';
};
$scope.resetDemo = function() {
// finally enter content that will raise a menu after everything is set up
$timeout(function() {
//var html = "Tell us something about this or add a macro like brb, omw, (smile)";
var htmlContent = $element.find('#htmlContent');
var html = "";
if (htmlContent) {
var ngHtmlContent = angular.element(htmlContent);
ngHtmlContent.html(html);
ngHtmlContent.scope().htmlContent = html;
// select right after the #
mentioUtil.selectElement(null, htmlContent, [0], 8);
ngHtmlContent.scope().$apply();
}
}, 0);
};
HTML :
<div class="share_tags fs-12">
<div class="row margin_row">
<div class="col-md-12 no_padding">
<div class="form-group">
<div contenteditable="true" mentio
mentio-typed-term="typedTerm"
mentio-macros="macros"
mentio-require-leading-space="true"
mentio-select-not-found="true"
class="editor tag" placeholder="Tell Us something about This"
mentio-id="'htmlContent'"
id="htmlContent"
ng-model="htmlContent">
</div>
</div>
<mentio-menu
mentio-for="'htmlContent'"
mentio-trigger-char="'#'"
mentio-items="tag"
mentio-template-url="/people-mentions.tpl"
mentio-search="searchTag(term)"
mentio-select="getTagText(item)"
></mentio-menu>
</div>
</div>
<script type="text/ng-template" id="/people-mentions.tpl">
<ul class="list-group user-search">
<li mentio-menu-item="tag" ng-repeat="tag in items" class="list-group-item">
<span ng-bind-html="tag.name | mentioHighlight:typedTerm:'menu-highlighted' | unsafe"></span>
</li>
</ul>
</script>
</div>
Reference link
http://jeff-collins.github.io/ment.io/?utm_source=angular-js.in&utm_medium=website&utm_campaign=content-curation#/
is working fine for me.
This is not working perfectly but for the time being i am using this code.
In app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function ($scope, $filter, $element) {
var tags;
$scope.allTags = ['Tag1', 'PrivateTag', 'Xtag', 'PublicTag1', 'newTag', 'socialTag', 'cricketTag'];
var replacedTag = '';
var replacedIndex;
var data;
$scope.log = function (name) {
$scope.tags = [];
$('ul').html(' ');
console.log("here", $('ul'))
var data = $('textarea').val();
replacedIndex = data.indexOf(replacedTag)
console.log('test', name, replacedTag, replacedIndex, data);
var replacedData = data.substring(0, replacedIndex - 1) + ' #' + name + data.substr(replacedIndex + replacedTag.length);
$('textarea').val(replacedData);
$('textarea').keyup();
}
f = $scope.log;
$('textarea').on('keyup', function (e) {
function getIndexOf(arr, val) {
var l = arr.length,
k = 0;
for (k = 0; k < l; k = k + 1) {
if (arr[k] === val) {
return k;
}
}
return false;
}
$('ul').html('');
$scope.tags = [];
tags = $(this).val().match(/#\S+/g);
console.log("---tags-", tags)
var a = data = $(this).val();
if (tags && tags.length) {
tags.forEach(function (tag,index) {
var index1 = getIndexOf(tags, tag);
console.log("index----",index, index1,tag)
replacedTag = tag;
$scope.tags = tag ? $filter('filter')($scope.allTags, tag.substr(1)) : [];
if ($scope.tags && $scope.tags.length && (e.keyCode && e.keCode != 32)) {
$scope.tags.forEach(function (tag1, index) {
$('ul').append('<li>' + '<a href="javascript:;" onclick=f("' + tag1 + '");>'
+ tag1 + '</a>' + '</li>')
})
}
else {
$('ul').html(' ');
}
if(index == index1) {
var b = a.substring(0, a.indexOf(tag) - 1) + ' <a>' + tag + '</a> ' + a.substr(a.indexOf(tag) + tag.length);
}
else {
var b = a.substring(0, a.lastIndexOf(tag) - 1) + ' <a>' + tag + '</a> ' + a.substr(a.lastIndexOf(tag) + tag.length);
}
a = b;
$('p').html(b)
})
}
})
});
HTML
<br>
<br>
<p></p>
<textarea rows="2" cols="80"></textarea>
<div>
<ul>
</ul>
</div>
For live demo Visit
https://plnkr.co/edit/SD9eouQa5yrViwxQD6yN?p=preview
i am also looking for the better answer.
I assume you're talking about gathering hash tags from a string of sorts, the snippet below demonstrates how you can build an array of #hashed tags without modifying the cursor position.
It uses a simple regular expression to match tags found in the textarea and then pushes them to an array.
var tags;
$('textarea').on('keyup', function(){
tags = $(this).val().match(/#\S+/g)
$('ul').html('');
tags.forEach(function(tag){
$('ul').append('<li>' + tag + '</li>')
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea></textarea>
<ul></ul>
how do you change a inner id with js and keep it the same id num (e.g hey1, bob2)
my js code
var obj = document.getElementById("chat").cloneNode(true);
var obj1 = document.getElementById("ch");
var obj2 = document.getElementById("chatbox");
var p = $(".chat");
var offset = p.offset();
num = num + 1;
if (num <=15) {
obj.id = obj.id + num; <--- **changing the id (this one works fine but the other two dont**
obj1.id = obj1.id + num; <--- changing the id
obj2.id = obj2.id + num; <--- changing the id
document.body.appendChild(obj);
document.body.appendChild(obj1);
document.body.appendChild(obj2);
var left = offset.left + 275;
document.getElementById("chat").style.left = left + "px";
tell me if i am doing it wrong but this was the easiest way i thought off
(ps i am a beginner at javascript)
thanks to all that try to help...
Edit
ok i clone this
<div class="chat" id="chat">
<div id="ch" class="ch">
<h2>Chat</h2></div>
<div class="chatbox" id="chatbox">
<div class="messages"></div>
<textarea id="message" class="chatinp"
rows="3" cols="27"></textarea>
<button class="send">Send</button></div>
</div>
and everytime it clones it changes the id of chat,ch and chatbox but keeping the original the same
like so...
clone1
<div class="chat" id="chat1">
<div id="ch1" class="ch">
<h2>Chat</h2></div>
<div class="chatbox" id="chatbox1">
<div class="messages"></div>
<textarea id="message" class="chatinp"
rows="3" cols="27"></textarea>
<button class="send">Send</button></div>
</div>
Clone2
<div class="chat" id="chat2">
<div id="ch2" class="ch">
<h2>Chat</h2></div>
<div class="chatbox" id="chatbox2">
<div class="messages"></div>
<textarea id="message" class="chatinp"
rows="3" cols="27"></textarea>
<button class="send">Send</button></div>
</div>
Not sure, but if I'm right, you're trying to create a new 'chatnode'. You'll have to traverse the childNodes array of the node you cloned to change id's. Try something like:
function cloneChat(){
var obj = document.getElementById("chat").cloneNode(true),
children = obj.childNodes
;
num += 1;
obj.id = obj.id+num;
if (num<16){
changeId(children,num);
}
//now appending obj to the document.body should be sufficient
document.body.appendChild(obj);
//change id recursively
function changeId(nodes, n){
for (var i=0;i<nodes.length;i=i+1){
if (nodes[i].childNodes){
changeId(nodes[i].childNodes,n);
}
if(nodes[i].id && /^ch$|^chatbox$/i.test(nodes[i].id)) {
nodes[i].id += String(n);
}
}
}
}
See this jsfiddle for a working example
Furthermore, this code won't work:
var p = $(".chat");
var offset = p.offset();
Because $(".chat") returns a list of nodes, where every node has it's own offset.
You seem to be using jQuery, so I suggest adding a 'jQuery' tag to your question. Maybe some jQuery whizzkid has a solution to offer.
In jQuery try to use
element.attr("id","newId");
See: http://api.jquery.com/attr/
How about this function?
function appendMe() {
var elementsToClone = ["chat"]; //Parent Elements to clone. This is the class name as well as the id
var childrenToHandle = new Array();
childrenToHandle["chat"] = ["ch"]; //Child elements mapping to keep sync. This is the class name as well as the id. Here we say that for the parent element chat, the inner elements to keep in sync is ch
var itemCount = 0;
for(i = 0; i < elementsToClone.length; i++) {
var refObj = document.getElementById(elementsToClone[i]);
if(refObj) {
$("." + elementsToClone[i]).each(
function() {
if(this.id.match(/\d+$/g)) {
itemCount = this.id.match(/\d+$/g);
}
}
);
var newObj = refObj.cloneNode(true);
newObj.id = elementsToClone[i] + ++itemCount;
var childrenArray = childrenToHandle[elementsToClone[i]];
if(childrenArray) {
$(childrenArray).each(
function() {
$(newObj).find("." + this).attr("id", this + itemCount);
}
);
}
document.body.appendChild(newObj);
}
}
}
Since you're already using jQuery in your code, how about:
var $obj = $("#chat").clone(),
$obj1 = obj.find("#ch"),
$obj2 = obj.find("#chatbox");
var p = $(".chat"),
offset = p.offset();
num = num + 1;
if (num <= 15) {
$obj.attr('id', $obj.attr('id') + num);
$obj1.attr('id', $obj1.attr('id') + num);
$obj2.attr('id', $obj2.attr('id') + num);
$('body').append(obj);
var newLeft = offset.left + 275;
$('#chat').css({
left: newLeft
});
}