JavaScript/jQuery

【jQuery/Traversing】.add(selector)

1Q74 2023. 3. 21. 10:37

1. Description

1 + 1 + 1 + ... + 1과 같은 개념이다. 매칭되는 Element를 단지 선택만 해 주는 메소드이다.
선택된 Element들의 CSS를 변경하거나 하는 등의 조작을 하지 않는다면 아무 변화도 일어나지 않는다.

.add(selector)
매칭된 Element들에 문자열로 표현된 selector를 추가적으로 선택한다.
→ #10, 11버튼
.add(elements)
매칭된 Element들에 하나 이상의 Element를 추가적으로 선택한다.
→ #20, 21버튼
.add(html)
매칭된 Element들에 html을 추가적으로 선택한다.
→ #30, 31버튼
.add(selection)
매칭된 Element들에 jQuery오브젝트를 추가적으로 선택한다.
→ #40, 41버튼
.add(selector, context)
context의 하위에 있는 문자열로 표현된 selector를 추가적으로 선택한다.
→ #50버튼

2. Example

#10,20,30,40버튼을 클릭하면 <td>중 짝수 인덱스를 선택하고 배경색을 변경한다.
#11,21,31,41버튼을 클릭하면 <td>중 홀수 인덱스를 선택하고 배경색을 변경한다.

#3버튼을 클릭하면 1행의 <td>에서 1~2번, 2행의 <td>에서 3~5번을 인덱스를 복사해서 행을 추가한 다음 배경색을 변경한다.


this.container = $("[name='_1q74-ex-1']");
this.containerElement = this.container[0];

this.selectors = {
    ex10: this.container
            .find("td[r1]:eq(0)")
            .add("td[r1]:eq(2)")
            .add("td[r1]:eq(4)"),
    ex11: this.container
            .find("td[r1]:eq(1)")
            .add("td[r1]:eq(3)")
            .add("td[r1]:eq(5)"),
    ex20: this.container
            .find(this.containerElement.querySelectorAll("td[r2]")[0])
            .add(this.containerElement.querySelectorAll("td[r2]")[2])
            .add(this.containerElement.querySelectorAll("td[r2]")[4]),
    ex21: this.container
            .find(this.containerElement.querySelectorAll("td[r2]")[1])
            .add(this.containerElement.querySelectorAll("td[r2]")[3])
            .add(this.containerElement.querySelectorAll("td[r2]")[5]),
    ex30: $("<td r3>3-1</td>")
            .add("<td r3>3-2</td>")
            .add("<td r3>3-3</td>")
            .add("<td r3>3-4</td>")
            .add("<td r3>3-5</td>")
            .add("<td r3>3-6</td>"),
    ex31: $("<td r4>4-1</td>")
            .add("<td r4>4-2</td>")
            .add("<td r4>4-3</td>")
            .add("<td r4>4-4</td>")
            .add("<td r4>4-5</td>")
            .add("<td r4>4-6</td>"),
    ex40: $("<td>").attr("r5", "").text("5-1")
            .add($("<td>").attr("r5", "").text("5-2"))
            .add($("<td>").attr("r5", "").text("5-3"))
            .add($("<td>").attr("r5", "").text("5-4"))
            .add($("<td>").attr("r5", "").text("5-5"))
            .add($("<td>").attr("r5", "").text("5-6")),
    ex41: $("<td>").attr("r6", "").text("6-1")
            .add($("<td>").attr("r6", "").text("6-2"))
            .add($("<td>").attr("r6", "").text("6-3"))
            .add($("<td>").attr("r6", "").text("6-4"))
            .add($("<td>").attr("r6", "").text("6-5"))
            .add($("<td>").attr("r6", "").text("6-6")),
    ex50: $("td:eq(0)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(0)")
            .add("td:eq(1)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(0)")
            .add("td:eq(2)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(0)")
            .add("td:eq(0)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(1)")
            .add("td:eq(1)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(1)")
            .add("td:eq(2)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(1)")
[1q74.tistory.com] javascript/jquery/traversing/add(selector)
1-1 1-2 1-3 1-4 1-5 1-6
2-1 2-2 2-3 2-4 2-5 2-6


3. Code

더보기
<!-- ---------------------------------------------------------
  --
  -- Author: 1q74.tistory.com
  --
  --------------------------------------------------------- -->
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>[1q74.tistory.com] javascript/jquery/traversing/add(selector)</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
</head>
<body>

	<div name="_1q74-ex-root">
		<div name="_1q74-ex-1">
			<table name="_1q74-tbl-ex-1" border="1">
				<tbody>
					<tr>
						<td r1>1-1</td>
						<td r1>1-2</td>
						<td r1>1-3</td>
						<td r1>1-4</td>
						<td r1>1-5</td>
						<td r1>1-6</td>
					</tr>
					<tr>
						<td r2>2-1</td>
						<td r2>2-2</td>
						<td r2>2-3</td>
						<td r2>2-4</td>
						<td r2>2-5</td>
						<td r2>2-6</td>
					</tr>
				</tbody>
			</table>

			<br/>

			<div name="_1q74-ex-bottom">
				<table border="1">
					<tr>
						<td colspan="2">
							<button name="btn-ex" selector="ex10">
								#10. $("td[r1]:eq(0)").add("td[r1]:eq(2)").add("td[r1]:eq(4)")
							</button>
							<button name="btn-ex" selector="ex11">
								#11. $("td[r1]:eq(1)").add("td[r1]:eq(3)").add("td[r1]:eq(5)")
							</button>
						</td>
					</tr>
					<tr>
						<td colspan="2">
							<button name="btn-ex" selector="ex20">
								#20. $("td[r2][0]").add("td[r2][2]").add("td[r2][4]")
							</button>
							<button name="btn-ex" selector="ex21">
								#21. $("td[r2][1]").add("td[r2][3]").add("td[r2][5]")
							</button>
						</td>
					</tr>
					<tr>
						<td colspan="2">
							<button name="btn-ex" selector="ex30">
								#30. $("&lt;td r3&gt;3-0&lt;/td&gt;").add(...).add("&lt;td r3&gt;3-4&lt;/td&gt;")
							</button>
							<button name="btn-ex" selector="ex31">
								#31. $("&lt;td r4&gt;4-1&lt;/td&gt;").add(...).add("&lt;td r4&gt;4-5&lt;/td&gt;")
							</button>
						</td>
					</tr>
					<tr>
						<td colspan="2">
							<button name="btn-ex" selector="ex40">
								#40.$("&lt;td&gt;").attr("r5", "").text("5-0").add(...).add($("&lt;td&gt;").attr("r5", "").text("5-4"))
							</button>
							<button name="btn-ex" selector="ex41">
								#41.$("&lt;td&gt;").attr("r6", "").text("6-1").add(...).add($("&lt;td&gt;").attr("r6", "").text("6-5"))
							</button>
						</td>
					</tr>
					<tr>
						<td colspan="2">
							<button name="btn-ex" selector="ex50">
								#50.$("td:eq(0)", $("tr:eq(0)").add(...).add("td:eq(5)", $("tr:eq(1)")
							</button>
						</td>
					</tr>
					<tr>
						<td>
							<input type="checkbox" name="chk-view-src" id="chk-view-src-1"/>
							<label for="chk-view-src-1">View Source</label>
						</td>
						<td>
							<button name="btn-init">Initialize</button>
						</td>
					</tr>
				</table>
			</div>
		</div>
	</div>

<script>
//
// _1q74 is a Namespace for preventing confliction of variable.
// It has not mean specially.
//
var _1q74 = {};
_1q74.example1 = {
	/////////////////////////////////////////////////////////////////
	//
	// Initialize container, selector, and the others
	//
	/////////////////////////////////////////////////////////////////
	initialize: function() {
		this.container = $("[name='_1q74-ex-1']");
		this.containerElement = this.container[0];

		this.selectors = {
			ex10: this.container
					.find("td[r1]:eq(0)")
					.add("td[r1]:eq(2)")
					.add("td[r1]:eq(4)"),
			ex11: this.container
					.find("td[r1]:eq(1)")
					.add("td[r1]:eq(3)")
					.add("td[r1]:eq(5)"),
			ex20: this.container
					.find(this.containerElement.querySelectorAll("td[r2]")[0])
					.add(this.containerElement.querySelectorAll("td[r2]")[2])
					.add(this.containerElement.querySelectorAll("td[r2]")[4]),
			ex21: this.container
					.find(this.containerElement.querySelectorAll("td[r2]")[1])
					.add(this.containerElement.querySelectorAll("td[r2]")[3])
					.add(this.containerElement.querySelectorAll("td[r2]")[5]),
			ex30: $("<td r3>3-1</td>")
					.add("<td r3>3-2</td>")
					.add("<td r3>3-3</td>")
					.add("<td r3>3-4</td>")
					.add("<td r3>3-5</td>")
					.add("<td r3>3-6</td>"),
			ex31: $("<td r4>4-1</td>")
					.add("<td r4>4-2</td>")
					.add("<td r4>4-3</td>")
					.add("<td r4>4-4</td>")
					.add("<td r4>4-5</td>")
					.add("<td r4>4-6</td>"),
			ex40: $("<td>").attr("r5", "").text("5-1")
					.add($("<td>").attr("r5", "").text("5-2"))
					.add($("<td>").attr("r5", "").text("5-3"))
					.add($("<td>").attr("r5", "").text("5-4"))
					.add($("<td>").attr("r5", "").text("5-5"))
					.add($("<td>").attr("r5", "").text("5-6")),
			ex41: $("<td>").attr("r6", "").text("6-1")
					.add($("<td>").attr("r6", "").text("6-2"))
					.add($("<td>").attr("r6", "").text("6-3"))
					.add($("<td>").attr("r6", "").text("6-4"))
					.add($("<td>").attr("r6", "").text("6-5"))
					.add($("<td>").attr("r6", "").text("6-6")),
			ex50: $("td:eq(0)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(0)")
					.add("td:eq(1)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(0)")
					.add("td:eq(2)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(0)")
					.add("td:eq(0)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(1)")
					.add("td:eq(1)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(1)")
					.add("td:eq(2)", "[name='_1q74-ex-1'] [name='_1q74-tbl-ex-1'] tr:eq(1)")
		};
		this.chkViewSource = this.container.find("[name='chk-view-src']");

		this.saveOriginalHtmlSource();
	},

	saveOriginalHtmlSource: function() {
		const _this = this;

		this.originalElements = {
			r10: this.selectors.ex10,
			r11: this.selectors.ex11,
			r20: this.selectors.ex20,
			r21: this.selectors.ex21,
			r30: this.selectors.ex30,
			r31: this.selectors.ex31,
			r40: this.selectors.ex40,
			r41: this.selectors.ex41,
		};

		this.clonedElements = {};
		$.each(this.originalElements, function(key, el) {
			_this.clonedElements[key] = el.clone();
		});
	},

	getTargetRowForBeingAddedRow: function(rowAttr) {
		const _this = this;

		let defaultRow = this.container.find("[name='_1q74-tbl-ex-1'] tr:eq(1)");
		const rowNumber = rowAttr.replaceAll(/[a-z]/g, "");

		let start = rowNumber - 1;
		let row;

		for(let i = start; i >= 2; i--) {
			row = _this.container.find("[name='_1q74-tbl-ex-1'] td[r" + i + "]");
			if(row.length > 0) break;
		}

		return row.parent();
	},
	
	/////////////////////////////////////////////////////////////////
	//
	// Execute example
	//
	/////////////////////////////////////////////////////////////////
	execute: function() {
		const _this = this;
		const btnExecute = this.container.find("[name='btn-ex']");

		function appendRow(elements, filter, style, rowAttr) {
			let targetRow;
			let isExists = false;
			let isStyled = false;

			const existElements = _this.container.find("[name='_1q74-tbl-ex-1'] td[" + rowAttr + "]");
			isExists = existElements.length > 0;
			isStyled = existElements.is("[style]");

			if(isExists && isStyled) return false;

			if(isExists && !isStyled) {
				elements.filter(filter).css(style);
				return true;
			} else {
				elements.filter(filter).css(style);
				targetRow = _this.getTargetRowForBeingAddedRow(rowAttr);
				targetRow.after($("<tr>").append(elements));
			}

			return true;
		}

		function change(selector, elements) {
			let targetRow;
			let isExists = false;

			switch(selector) {
				case "ex10":
					elements.css({ background: "#1FEC99" });
					break;

				case "ex11":
					elements.css({ background: "#81C0E8" });
					break;

				case "ex20":
					elements.css({ background: "#8434A4" });
					break;

				case "ex21":
					elements.css({ background: "#34A485" });
					break;

				case "ex30":
					if(!appendRow(elements, ":even", { background: "#8B71F3" }, "r3")) {
						return false;
					}
					break;

				case "ex31":
					if(!appendRow(elements, ":odd", { background: "#FF5733" }, "r4")) {
						return false;
					}
					break;

				case "ex40":
					if(!appendRow(elements, ":even", { background: "#DEA85F" }, "r5")) {
						return false;
					}
					break;

				case "ex41":
					if(!appendRow(elements, ":odd", { background: "#6C7908" }, "r6")) {
						return false;
					}
					break;

				case "ex50":
					const existElements = _this.container.find("[name='_1q74-tbl-ex-1'] td[r7]");
					isExists = existElements.length > 0;
					isStyled = existElements.is("[style]");

					if(isExists && isStyled) return;

					if(isExists && !isStyled) {
						existElements.filter(":lt(3)").css({ background: "#89979A" });
						existElements.filter(":gt(2)").css({ background: "#D43E68" });
						return;
					} else {
						const clonedElements = elements.clone();
						clonedElements.removeAttr("r1").removeAttr("r2").attr("r7", "");
				
						if(typeof _this.originalElements["r50"] == 'undefined') {
							_this.originalElements["r50"] = clonedElements;
							_this.clonedElements["r50"] = _this.originalElements["r50"].clone();
						}

						clonedElements.filter(":lt(3)").css({ background: "#89979A" });
						clonedElements.filter(":gt(2)").css({ background: "#D43E68" });
						targetRow = _this.getTargetRowForBeingAddedRow("r7");
						targetRow.after($("<tr>").append(clonedElements));
					}

					break;
			}

			_this.refreshSourceView();
		}

		btnExecute.click(function() {
			const selector = $(this).attr("selector");
			const elements = _this.selectors[selector];
			change(selector, elements);
		});
	},

	/////////////////////////////////////////////////////////////////
	//
	// Control example
	//
	/////////////////////////////////////////////////////////////////
	refreshSourceView: function() {
		const _this = this;
		let isChecked = _this.chkViewSource.is(":checked");

		if(isChecked) {
			for(let i = 1; i <= 2; i++) {
				_this.chkViewSource.prop("checked", (isChecked = !isChecked));
				_this.toggleHtmlToSource();
			}
		}
	},

	toggleHtmlToSource: function() {
		const _this = this;
		const isChecked = this.chkViewSource.is(":checked");

		if(isChecked) {
			$.each(this.originalElements, function(key, entries) {
				entries.each(function(i, el) {
					const element = $(el);
					const html = $("<div>").append(element.clone()).html();
					const specialCharHtml = $("<div>").text(html).html();
					element.html(specialCharHtml);
				});
			});
		} else {
			$.each(this.originalElements, function(key, entries) {
				entries.each(function(i, el) {
					const element = $(el);
					const html = $(_this.clonedElements[key][i]).html();
					element.html(html);
				});
			});
		}
	},

	control: function() {
		const _this = this;

		this.chkViewSource.click(function() {
			_this.toggleHtmlToSource();
		});

		const btnInitialize = $("[name='_1q74-ex-bottom'] [name='btn-init']");
		btnInitialize.click(function() {
			$.each(_this.originalElements, function(key, entries) {
				entries.each(function(i, el) {
					const element = $(el);
					element.removeAttr("style");
				});
			});
			_this.refreshSourceView();
		});
	}
}

_1q74.example1.initialize();
_1q74.example1.execute();
_1q74.example1.control();
</script>
<style>
[name="_1q74-ex-root"] {
	min-height: 200px;
}

[name="_1q74-ex-1"] {
	min-height: 170px;
}

[name="_1q74-ex-bottom"] {
	min-height: 150px;
}

[name="_1q74-ex-1"] td {
	min-width: 30px;
	min-height: 30px;
	width: 120px;
}

[name="_1q74-ex-bottom"] tbody {
	max-width: 400px;
}

[name="_1q74-ex-bottom"] td {
	width: 300px;
}

[name|="_1q74-ex"] button {
	background: lightgray;
	border: 5px outset;
	min-height: 40px;
	width: 100%;
}

[name|="_1q74-ex"] button:active {
	border: 5px inset;
	min-height: 40px;
	width: 100%;
}
</style>

</body>
</html>

3. File

[javascript][jquery][traversing]add.html
0.01MB


4. Reference

https://api.jquery.com/add/