본문 바로가기

자바스프링웹공부(2024)/자바스크립트

2024.08.26. JS - 익명함수사용, onload 이벤트, 라디오-체크박스 값출력

반응형

* 스크립트 코드 실행 시점문제

- html 파일내에 있는 img 태그의 1.jpg 사진을 스크립트를 실행하여 2.jpg로 바꾸려고 하는데 실행이 안됨.

<script src="test3_study.js"></script>
</head>
<body>
	<h1>test3.jsp</h1>
	<img src="../images/1.jpg" id="img1" width="150" height="150" >
<body>
/* test3_study.js */
function myFunction(){
	document.getElementById("img1").src = "../images/2.jpg";
}

문제점 : 

 => 현재 test3.js 파일을 로딩하는 위치가 <head> 태그 내이므로 현재 스트립트가 실행되는 시점에는 <body> 태그 내의 요소들이 로딩되기 전이다.
=> 따라서, 해당 요소들에 접근하는 코드사용시 요소에 대한 객체가 없으므로 null 값이 리턴되고 이 객체에 접근하기 위한 코드가 실행 될때 null 값을 통한 접근이 불가능하여 오류 발생함.
=> img1 객체가 존재하지 않으므로(=null) img1.src 속성에 접근이 불가능하다!
     img1.src = "../images/2.jpg"; // 오류 발생위치
=> 해당 오류 메시지 : TypeError: Cannot set properties of null (setting 'src')

 

해결책 1번) 해당 요소 태그보다 아래쪽에 스크립트 기술 

<script type="text/javascript">
	let img1 = document.getElementById("img1");
	img1.src = "../images/2.jpg";
</script>

 

해결책 2번) 스크립트 코드위치와 상관없이 모든 요소 로딩이 완료된 후 스크립트 실행되도록 하기 

           2-1) 함수를 정의한 후 jsp파일의 <body> 태그에 onload 이벤트를 활용하여 해당함수 호출하기

<body onload="myFunction()">

해결책 2-2번) <body> 태그는 그대로 두고 자바스크립트 window.onload 속성을 이벤트로 활용하여 해당 이벤트가 발생하면 실행할 함수를 속성값으로 전달하기
             => window.onload = 함수명; 
              => 주의! 함수명뒤에 소괄호를 기술하지 않는다! (=즉시 호출하는 것이 아니기 때문!)

/* test3_study.js 파일내에 */
window.onload = myFunction;


                => onload 이벤트가 발생하는 시점에 myFunction 함수가 실행됨.
                => 주의  window.onload = myFunction(); // 오류! TypeError: Cannot set properties of null (setting 'src')
                => 현재 코드가 로딩되는 시점에 함수를 실행시킴
                => 즉, onload 이벤트와 관계없이 myFunction 함수가 실행이 되어 버리기 때문에 오류 발생.

해결책 2-3번) window.onload 이벤트 뒤에 별도의 함수를 전달하지 않고 익명함수를 직접구현하는 방법.
=> 익명함수란? 함수 정의 시 함수의 이름이 없는 함수
 => 따라서 ,별도로 정의해 놓고 호출하는 함수가 아닌 특정 속성에 전달하는 등의 실행할 위치에서 정의까지 한꺼번에 수행하는 경우에 사용하는 함수 형태

// 익명함수 형태 : window.onload = function() { .... }
window.onload = function() {
    let img1 = document.getElementById("img1");
    img1.src = "../images/2.jpg";
}; // 마지막 세미콜론은 생략해도 무관함.(다만 원래 window.onlad = x; 이므로 세미콜론이 포함됨.)

*  익명함수는 보통 언제 쓰는가? 함수가 일회용 일 때 


[ form 태그 내의 각 요소에 접근하는 방법 ]
1) 기존의 document.querySelector() 메서드 등을 활용하여 해당 요소를 직접 지정하는 방법 또는
2) form 태그를 통해 폼 내의 요소에 접근하는 방법
   - document.form태그의name속성값.접근할태그의name속성값.속성명 또는
     document.form태그의name속성값.접근할태그의name속성값.메서드명()
 => 속성명 : name, type, value 등
 => 메서드 : focus() - 대상 요소에 커서(포커스) 요청
               blur() - 대상 요소에서 커서(포커스) 해제
                 select() - 대상 요소에 포커스 요청 및 입력 항목 블럭 지정

 

● form 태그 내의 각 요소에 접근하는 방법 예제

<h1>test5.jsp - form 태그 이벤트</h1>
<form action="test5_result.jsp" name="fr">
	텍스트 <input type="text" name="text1">
	<input type="button" value="focus" id="btnFocus">
	<input type="button" value="select" id="btnSelect">
	<br>
	숨김텍스트 <input type="password" name="text2">
	<br>
	멀티라인텍스트 <textarea rows="5" cols="20" name="ta"></textarea>
	<br>
		<input type="button" value="입력값 출력" id="btnShowInfo">
		<input type="button" value="입력값 체크" id="btnCheck">
		<input type="submit" value="입력값 전송" id="btnSubmit">
</form>
<div id="infoArea"></div>

 

// id 선택자 "btnCheck" 버튼 클릭 이벤트 처리 => 익명함수로 처리
document.querySelector("#btnCheck").onclick = function() {
    let text1 = document.fr.text1.value;
    let text2 = document.fr.text2.value;
    let ta = document.fr.ta.value;
    // form 태그 입력 항목 3개중 입력되지 않는 항목 존재 여부 판별

    // => 기본적으로 submit 버튼과 입력 항목의 required 속성 조합하여 간단하게 구현 가능하지만
    // 	    추가적인 작업(입력값 규칙 검증 등)을 수행해야 할 경우
    // 		자바 스크립트를 통해 별도의 코드로 추가작업 구현가능
    // => 	1) 입력항목(value 속성값)이 널스트링("")인지 판별
    //		2) 입력항목(value 속성값)의 문자열 길이 (length 속성값)가 0인지 판별
    // => 	첫번째 텍스트 입력확인하여
    // 		미입력 시 "첫번째 텍스트 입력 필수!" 메세지 출력하고 해당 입력창에 커서 요청
    //		아니면, 두번째 텍스트 입력 확인하여
    // 		미입력 시 "두번째 텍스트 입력 필수!" 메세지 출력하고 해당 입력창에 커서 요청
    //		아니면, 세번째 텍스트 입력 확인하여
    // 		미입력 시 "세번째 텍스트 입력 필수!" 메세지 출력하고 해당 입력창에 커서 요청
    // 모두 아니면 "모든 텍스트 입력완료"" 메시지 출력
    if(document.fr.text1.value == ""){
        alert("첫번째 텍스트 입력 필수!");
        document.fr.text1.focus();
    } else if(document.fr.text2.length == 0){
        alert("두번째 텍스트 입력 필수!");
        document.fr.text2.focus();
    } else if(document.fr.ta.value == ""){
        alert("세번째 텍스트 입력 필수!");
        document.fr.ta.focus();
    } else {
        alert("모든 텍스트 입력완료!");
    }
    /* else 안쓰는 방법 */
    // if문과 else if 문 등의 조합을 통해 판별을 수행한 후 
    // 해당하지 않는 조건에 대한 나머지 모든 작업은 if 문 밖에서 수행하려면
    // if 문 블럭마다 작업 완료 후 함수를 종료하도록 rueturn을 기술하면 된다
    // => return 문을 만나면 함수 실행이 즉시 종료 되므로 if 문 밖의 문장이 실행되지 않는다.!
    if(document.fr.text1.value == ""){
        alert("첫번째 텍스트 입력 필수!");
        document.fr.text1.focus();
        return; // 현재 함수 실행이 즉시 종료됨.
    } else if(document.fr.text2.value == ""){
        alert("두번째 텍스트 입력 필수!");
        document.fr.text2.focus();
        return;
    } else if(document.fr.ta.value == ""){
        alert("세번째 텍스트 입력 필수!");
        document.fr.ta.focus();
        return;
    }
    /* 익명함수는 return 이 끝나면 돌아갈 곳이 없다. 근데 onclick 이벤트에 걸려있다.
        if문에서 return을 쓰면 아래에 있는 alert 실행하지않고 함수를 끝내버린다. 
     */
    alert("모든 텍스트 입력완료!"); // 위의 if문 조건이 다 맞지 않으면 return이 실행되지 않으니까 실행이 될것이다.
    // return을 넣은 것과 else 의 역할이 똑같다.
    // 모든 값이 입력됐을때 submit 버튼과 동일한 동작을 수행하려면
    // 해당 form 태그 요소의 submit 메서드를 호출함녀 된다.
    document.fr.submit(); /* 체크버튼을 눌러도 submit 동작이되어 넘어간다. 버튼을 button으로 만들어도 submit 버튼으로 만든것과 똑같은 기능을 하는 것이다. */ 
}

● 라디오박스, 체크박스 값출력하기

<h1>test6.jsp - form 태그 이벤트</h1>
	<form action="test6_result.jsp" name="fr">
<!-- 라디오버튼에 requeire 속성 지정시 동일한 그룹내에서 하나만 선택하면 됨. -->
<!-- 이거는 두개 다  걸어도 한개만 선택하면 됨. -->
<input type="radio" name="radio" value="라디오값1">라디오1
<input type="radio" name="radio" value="라디오값2">라디오2
<input type="button" value="라디오버튼 선택완료" id="btnRadio">
<hr>
<!-- 체크박스에 ruquired 속성 지정시 동일한 그룹 상관없이 해당 항목은 무조건 선택해야 한다.  -->
<!-- 3개 걸면 3개다 선택해야 함. 하나라도 체크하지 않았을 경우 submit 동작 수행불가.-->
<!-- 다 선택해야하는 것아니면 체크박스는 required 안써야 함. -->
체크박스
<input type="checkbox" name="check" value="체크박스값1">체크박스1
<input type="checkbox" name="check" value="체크박스값2">체크박스2
<input type="checkbox" name="check" value="체크박스값3">체크박스3
<input type="checkbox" name="all_check" id="all_check"><label for="all_check">전체선택</label>
<input type="button" value="체크박스 체크완료" id="btnCheckbox">
<input type="submit" value="전송">
</form>
<div id="infoArea"></div>

 

window.onload = function() {
	// 라디오버튼 선택완료 버튼 클릭 이벤트 핸들링(처리)
	document.getElementById("btnRadio").onclick = function(){
		// 라디오버튼(name속성명 radio)에 접근하여 value 속성값 출력
		// 라디오 버튼의 배열 중 첫번째 요소(인덱스 0)의 value와 checked 속성값 출력
		console.log(document.fr.radio[0].value); // 첫번째 라디오버튼의 value속성값
		console.log(document.fr.radio[0].checked);// 첫번째 라디오버튼의 checked속성값(선택여부)
		// 위의 코드에서 라디오버튼 접근을 위해 선택된 객체(배열)를 변수에 저장하여 중복코드 제거
		let arrRadio = document.fr.radio; // radio button 관리하는 배열을 변수에 저장
		document.querySelector("#infoArea").innerText = 
				arrRadio[0].value + " : " + arrRadio[0].checked + "\n" 
				+ arrRadio[1].value + " : " + arrRadio[1].checked;
		// 위의 코드에서 배열 접근 방식을 for문으로 변환(기본 배열 접근 공식 활용)
		let radioInfo = "";
		for(let i of document.fr.radio){
		//	console.log(i.value + " : " + i.checked)
			radioInfo += i.value + " : " + i.checked;
			console.log("radioInfo : " + radioInfo);
		}
		//-----------------
		// 만약, 두개의 라디오버튼 중 하나도 선택하지 않았을 경우
		// "라디오버튼항목선택필수" 경고창 출력
		if(document.fr.radio[0].checked == "false" && document.fr.radio[1].checked == "false" ) {
			alert("라디오버튼항목선택필수");
		}
	}
	// !!!!체크박스버튼 체크완료 버튼 클릭 이벤트 핸들링(처리) : 체크박스 처리 방법은 기본적으로 라디오버튼과 동일함.
	
	// 전체선택 체크박스 클릭 이벤트 핸들링
	document.fr.all_check.onclick = function() {
		// 전체선택 체크박스가 "체크"상태일 경우
		// => 다른 체크박스 3개를 모두 "체크"상태로 변경하고
		// 아니면, 모두 "체크해제" 상태로 변경
		if(!document.fr.all_check.checked) { // 야임마 boolean 조심해라!!
			for(let i of document.fr.check){
				i.checked = false;				
			}
		} else {
			for(let i of document.fr.check){
				i.checked = true;
			}
		}
		//-------------------
		// 전체선택 체크박스의 체크상태(true/false)와 각 체크박스의 체크상태가 동일하므로
		// if 문을 통한 판벽없이 전체선택 체크박스의 체크상태값을 각 체크박스의 상태값으로 설정해도 된다.
		for(let i of document.fr.check) {
			i.checked = document.fr.all_check.checked;
		}
		for(let i = 0; i < document.fr.check.length; i++){
			document.fr.check[i].checked = document.fr.all_check.checked; // true이면 true이다.
		}
	}
}
반응형