728x90
728x90
맨날 까먹어서 검색하는 text-decoration ....

 

특정 부분의 text-decoration 없애기

html에서 쓰는 인라인 태그 방식은 아래와 같다.

style="text-decoration:none"
<a href="http://www.google.co.kr/" style="text-decoration:none">Google 검색</a>

 

css에서 쓴다면 아래와 같다. 적용되지 않는다면 !important를 세미콜론 앞에 추가해준다.
hover는 마우스를 대상물 위에 얹었을 때이다.

a { text-decoration:none !important }
a:hover { text-decoration:none !important }

 

 

 

모든 a태그의 text-decoration 없애기

css에서 아래와 같이 걸어준다.

a { text-decoration:none }

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
중복요청 방지가 필요한 이유는 중복결제, 같은 내용 추가/등록 등을 막기 위함

 

 

jQuery.ajax() 중복요청 처리 방지하기

 

 

1

ajax 가 완료되기 전에 다시 클릭하였을 때 해당 요청 진행을 막는 코드
상태 변수를 만들어 전송 유무에 따라 Ajax 요청을 하거나 차단한다.

 

var isRun = false;

function abcde() {
    
    if(isRun == true) {
        return;
    }
    
    isRun = true;
    
    $.ajax({
 
        ...
 
    }, success : function(datas) {
        
        isRun  = false;
 
        ...
 
    });
}

 

 

2

또는 ajax 세팅 옵션에 async : false를 추가한다. (동기 처리)
동기로 처리하게되면 버튼을 눌러 request 요청을 날렸을 때 response 요청이 올 때까지
다른 request 요청은 받지 않게 되어 중복호출을 방지한다. 

 

async : false;

 

 

3

또는 버튼에 클릭 이벤트를 jQuery.bind(), jQuery.unbind() 로 처리해 클릭 이벤트를 bind 시켜놓는다. (클릭의 비활성화) 한 번 클릭시 클릭 이벤트를 unbind 시키고, ajax 요청이 끝나면 다시 bind 시킨다.

 

$(document).ready(function() {
	$('#foo').bind('click', function() {
		doSomething();  
	});
});
 
var doSomething = function(){
	$('#foo').unbind('click');
  
	$.ajax({
		type: "POST",
		url: "some.do"
	}).done(function() {
		$('#foo').bind('click', function() {
			doSomething();  
		});    
	});
}


// 출처: https://javafactory.tistory.com/146 [FreeLife의 저장소]


 

 

4

setTimeout() 메소드 사용하여 중복을 막았다.  

 

// 클릭 후 읽을 부분
if(dontDouble) {
	return;
}
dontDouble = true; 

//아래는 ajax. success, error function 사이에 넣는다
setTimeout(function() { dontDouble = false; }, 10000);

 

 

5

중복처리를 해결할 수 없다면 마지막 success 값만 실행한다.

 

var ajax_last_num = 0; // 마지막 요청 카운트 저장. 전역변수 

// ajax 요청 시작 전 ajax 요청이 들어있는 함수의 지역변수 
var current_ajax_num = ajax_last_num;

// ajax 중복요청왔을때 계속 ajax success 코드실행을
// 방지하기 위해 지금 들어온 요청의 카운트 저장 

$.ajax({ 
	dataType: "html", 
	type:'get', 
	url: url, 
	beforeSend:function(request){ 
		ajax_last_num = ajax_last_num + 1; // 요청의 마지막 count 를 +1 
		//요청 전 실행되야할 코드 
	}, 
	success:function(request){ 
		if(current_ajax_num == ajax_last_num - 1){ // 현 요청이 마지막 요청인지 확인
		//성공했을때 동작해야될 코드
} 
});

// 출처: https://darammg.tistory.com/5 [다람쥐의 경험들]

 

 

 

6

기타 방법으로는 클릭할 버튼을 disable 시키거나 body 부분 위에 반투명 레이어와 로딩 이미지를 띄우는 jQuery BlockUI 플러그인을 사용하는 방법이 있다.

 

 

중복 방지를 위해서 프론트와 벡엔드에서 각각 해야할 것

프론트 JS에서는 preventDefault()나 attr('disabled', true) 등을 사용해서 "버튼 클릭" 직후의 중복 발송처리 방지,
백엔드에서는 요청/응답에 타임스탬프를 넣거나 특정 토큰을 발급하거나 하는 방식으로 중복 요청처리 방지. 얼마나 완벽하게 더블서브밋을 방지해야 하느냐에 따라서 로직은 다양

 

참고하면 좋을 내용

ajax 호출 시 로딩이미지 출력하기

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

간수치기 높아져서 간약을 먹고 있는데요...그러다보니 바짝 신경쓰이게 되는 간 건강...좋은 내용이 들은 간경변 간경화 등 간건강 관련 도움된다는 비타민D관련 기사를 모아봤습니다. 비타민D는 대표적으로 칼슘과 인의 대사에 필수 인자로 뼈 형성과 근육활동에 절대적인 기능을 해주며, 인체 대부분의 조직과 세포를 수리,복구하고 유지하고 유전자의 발현에 영향을 주고 조절을 담당해주는데요.

 

 

 

 다양한 종류의 염증을 예방하는데 도움을 주는 특정 항균 펩티드를 증가시켜 우리 몸 스스로 항생 역활을 할 수 있도록 도와주는 항생제 기능도 있습니다. 그에 그치지 않고 유전자 변이에 의한 암세포가 확산되는 것을 막아주고, 다른 곳으로 침투하여 전이되는 가능성을 낮춰주는 세포분화 증대기능도 있어 신경써야 하는 비타민이지요.

 


 

간경변 증상 완화에 탁월한 비타민D

2015.12.17   쿠키뉴스 / 솔크 생물학 연구소의 Ronald M. Evans 교수

 

흔히 간경변, 간경변증으로 알려져 진 ‘간섬유증’은 간의 염증과 손상이 만성적으로 지속되어 본래의 건강한 모습으로 복귀가 불가능해질 정도로 간이 울퉁불퉁해진 상태를 말한다. 한번 간섬유증이 발생하면 간 기능이 계속 떨어지는 데다, 간성뇌증, 간암으로 이어질 수 있어 주의가 필요하다. 가장 중요한 것은 간섬유증 치료에 효과적인 약물이 없다는 점이다. 그런데 최근 간섬유증에 비타민D가 효과적이라는 사실이 알려져 대중들의 관심을 끌고 있다.  

솔크 생물학 연구소의 Ronald M. Evans 교수는 비타민D가 간섬유화를 멈춘다는 임상시험 결과를 발표했다. 이에 대해 Evans 교수는 “비타민D 수용체가 간 섬유화 활성인자를 방어하는 역할을 한다”며 “정상 간으로 완전히 회복시키지 못해도 비타민D가 적어도 간경화 악화를 막아준다”고 밝혔다.

 


 

비타민 D가 지방간을 예방하는 이유


2015/02/04  LA중앙일보 / 임대순  연세클리닉 원장

 

간에 지방이 많이 쌓인 상태를 지방간이라고 한다. 지방간은 '알코올성 지방간'과 '비알코올성 지방간'이 있다. 알코올성 지방간은 알코올을 분해할 때 생기는 독성물질인 아세트알데하이드가 간세포를 망가뜨림으로 간기능이 저하되어, 음식에서 섭취된 지방이 간에서 빠져나오지 못하고 간에 쌓이게 되는 것이며, 비알코올성 지방간은 당뇨, 고혈압, 콜레스테롤, 고지혈증, 그리고 비만과 함께 오는 대사증후군이 원인이다. 이들 대사증후군으로 인해 간기능이 저하되어 간에 기름이 쌓이게 되므로 지방간이 되며 당연히 간염, 간경화, 간암의 원인이 된다.

대사증후군에 대해 알게 되면 비알코올성 지방간을 이해하게 되고 비만도 간암의 원인이 될 수 있는 이유를 알게 된다. 따라서 비알코올성 지방간을 예방하기 위해선 대사증후군의 원인을 알아야 하는데, 바로 이 부분에서 비타민 D의 또 다른 역할이 드러나는 것이다.

대사증후군의 근본 원인은 '인슐린 저항성'이다. 인슐린 저항성이란 혈당을 낮추는 인슐린에 대해 몸이 제대로 반응을 하지 못해 인체 세포가 혈액 내 포도당을 잘 이용하지 못하게 되므로 혈당이 높아지니 더욱 많은 인슐린이 분비되고 따라서 여러 가지 문제를 일으키는 것이다. 그런데 이 인슐린 저항성은 우리 몸의 비타민 D가 부족하면 더욱 심해진다. 따라서 비타민 D를 충분히 섭취하고 비만하게 되지 않도록 좋은 식습관을 유지하면서 적절한 운동을 하면 인슐린 저항성뿐 아니라 대사증후군, 더 나아가 지방간을 예방할 수 있는 것이다. 필자는 이미 고혈압, 당뇨, 고지혈증 등에 대한 비타민 D의 예방 효과를 지난 칼럼들에서 알려드린 바 있다.

간은 재생력이 매우 강하다. 그러므로 "간세포가 죽는다"는 표현은 맞지 않는다. 간경화는 간세포가 죽어서 생기는 것이 아니라 간 속의 섬유아세포(stellate cell)가 '근육섬유아세포(myofibroblast)'로 되어, 이 변화된 세포가 죽지 않고 지속해서 섬유질을 만들고 또 만들어, 마치 노끈이 목을 옥죄듯 간세포에 피의 흐름을 점차 안 통하게 만들어 버리는 것이다. 비타민 D는 간경화를 완전하게 정상 간으로 회복은 못 시켜도 적어도 간경화의 악화는 막아준다.

 


 

비타민D, 간암 억제 효과

 

2014.06.10 경향신문
세계보건기구(WHO) 산하 국제암연구소(IARC), 영국 임피어리얼 칼리지 런던(ICL), 
미국 에모리 대학의 국제연구진

 

세계보건기구(WHO) 산하 국제암연구소(IARC), 영국 임피어리얼 칼리지 런던(ICL), 미국 에모리 대학의 국제연구진은 타민D가 간암의 대부분을 차지하는 간세포암(HCC) 위험을 절반 가까이 낮추어 주는 효과가 있다는 연구결과를 발표했다.

유럽 암·영양 전향연구(EPIC)에 참여한 52만여명과 연구 진행 중 간암이 발생한 138명의 자료를 분석한 결과혈중 비타민D 수치 상위 30% 그룹이 하위 30% 그룹에 비해 간세포암 발생률이 49% 낮은 것으로 나타났다고 연구팀을 이끈 에모리 대학 보건대학원의 베로니카 페디르코 박사가 밝혔다. 과거의 간 손상 병력과 만성 B형, C형 간염 등 간암 위험인자들을 고려했지만 이 결과에는 변함이 없었다.

비타민D는 이 밖에도 대장암 등 다른 여러 종류의 암 예방에도 도움이 된다는 과학적 증거들이 점점 증가하고 있지만 암 예방을 위해 비타민D 보충제 복용을 권장하기엔 아직 증거가 더 필요하다고 페디르코 박사는 강조했다. 이 연구결과는 ‘간장병학’(Hepatology) 최신호(6월6일자)에 실렸다.

 


 

비타민 D 결핍, B형 간염 바이러스 확산 촉진


2014/12/17     후생닷컴비타민 D 결핍이 B형 간염 바이러스의 확산을 촉진할 수 있다.



세계보건기구 조사에 따르면 세계적으로 B형 간염에 감염된 사람이 20억 명에 달하고 매년 60만 명이 B형 간염으로 사망하고 있는데 비타민 D 결핍이 높은 혈중 바이러스 수치와 관련이 있다는 연구결과가 발표됐다. 

비타민 D는 건강한 면역체계를 유지하는데 도움이 될 수 있으며 C형 간염바이러스 감염을 비롯한 염증성 간질환 및 대사성 간질환과 관련이 있다는 보고가 있었지만 비타민 D의 대사가 만성 HBV 감염에 어떤 영향을 주는지는 밝혀지지 않았다. 

요한 볼프강 괴테 대학병원(Johann-Wolfgang-Goethe University Hospital)에서 2009년 1월부터 2010년 12월까지 치료받은 적이 없는 만성 B형 간염 바이러스 보균자 203명에게 HCV과 HDV, HIV 감염 여부와 음주량을 조사하고 25-hydroxyvitamin D 수치를 측정한 결과 81%는 비타민 D 결핍이었고 혈중 HBV DNA 수치가 비타민 D 결핍의 지표인 것으로 확인됐다.

HBV DNA 수치가 2000 IU/mL 미만인 환자는 비타민 D 수치가 평균 17 ng/mL이고 HBV DNA 수치가 2000 IU/mL 이상인 환자는 비타민 D 수치가 평균 11 ng/mL이었으며 HBeAg 양성인 환자는 HBeAg 음성인 환자보다 비타민 D 수치가 낮았다.

 


 

혈중 비타민D 수치 낮으면 B형 간염 감염률 ↑

 

2013-07-30   약업신문

독일 요한 볼프랑 괴테대학 부속병원의 크리스티안 M. 랑게 박사 연구팀(내과의학)
미국 간질환연구협회(AASLD) 발간 학술저널 ‘간장병학’誌(Hepatology) 최근호 게재

 

비타민D가 B형 간염을 예방하는 데 효과적일 수 있음이 시사됐다. 혈중 25-히드록시비타민D 수치가 낮은 만성 B형 간염 환자들의 경우 혈중 25-히드록시비타민D 수치가 높은 대조그룹에 비해 B형 간염 바이러스 감염률이 높게 나타났다는 조사결과가 공개된 것. 독일 프랑크푸르트에 소재한 요한 볼프랑 괴테대학 부속병원의 크리스티안 M. 랑게 박사 연구팀(내과의학)은 미국 간질환연구협회(AASLD)가 발간하는 학술저널 ‘간장병학’誌(Hepatology) 최근호에 게재한 보고서를 통해 이 같이 밝혔다.  보고서의 제목은 ‘만성 감염환자들에게서 나타난 낮은 혈중 비타민D 수치와 높은 B형 간염 바이러스 복제의 상관성’.

 랑게 박사팀은 치료전력이 없는 총 203명의 만성 B형 간염 바이러스 감염환자들을 대상으로 조사작업을 진행했었다. 그 결과 34%(69명)가 중증 비타민D 결핍(혈중 25-히드록시비타민D 수치 10ng/mL 미만), 47%(95명)가 비타민D 결핍(혈중 25-히드록시비타민D 수치 10ng/mL 이상 20ng/mL 미만)인 것으로 파악됐다. 이와 함께 전체의 19%(39명)만이 혈중 25-히드록시비타민D수치가 20ng/mL 이상이어서 혈중 비타민D 수치가 충분한 수준을 보인 것으로 분석됐다.

[ (주) _ 2013년까지 20~100을 정상수준(충분한)으로 보고 있었군요. 그러다가 2014년도에는 30이상과 20이상이란 참고치가 섞여 사용되다, 2015년부터 확실히 30이상을  정상범위로 통일되었음을 알 수 있습니다. ] 

또한 B형 간염 e항원(HBeAg) 양성 환자들의 경우 혈중 25-히드록시비타민D₃ 수치가 HBeAg 음성 환자들에 비해 낮게 나타났다. 이 뿐 아니라 B형 간염 바이러스 DNA의 혈중 농도를 측정한 결과 햇빛 조사량(照査量 )이 적은 계절에 높게 나타나는 반비례 양상을 보였다. 랑게 박사는 “만성 B형 간염 환자들에게서 낮은 혈중 25-히드록시비타민D 수치가 높은 B형 간염 바이러스 복제율과 밀접한 관련이 있는 것으로 보인다”고 결론지었다. 반면 혈중 비타민D 수치와 C형 간염 바이러스 부하와는 상관성이 없는 것으로 나타났다고 덧붙였다.

 


 

 

비타민D 섭취방법

 

바람직한 비타민D 섭취방법은 음식과 햇빛을 통한 방법입니다. 계란이나 생선, 간같은 음식을 통해서도 섭취할 수 있지만 필요한 양의 10%밖에 충족을 못 시키기때문에 햇빛을 통해 피부로 광합성을 하는것이 가장 좋다고 합니다. 직장인들이나 학생 등 실내에 있는 시간이 기신 분들 신경써서 햇빛을 쬐어주어야 된다는 이야기예요. 

 

 

 

 

음식외에 비타민D섭취방법에는 보충제, 햇빛, 조사기 등으로 널리 알려진 방법은 보충제지만 보충제로 먹는것은 비타민D의 수치가 크게 오르지 않아 정상 수치로 오르기가 힘들고 부작용과 장기 복용시 중독중을 일으킬 수 있어 주의가 필요하다고 하네요.

 

 

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
textarea 텍스트 입력 영역 비활성화, 활성화 예제
$("#textarea").attr("readonly", true);

$(".edit").click(function(event) {
	$("#textarea").attr("readonly", false);
});

 

크롬에서는 상관없으나 익스플로러에는 커서가 깜박여서 활성화된 듯한 착각을 불러일으키므로 포커스를 제거해준다onfocus="this.blur()" 를 사용하거나 disabled를 이용해준다.

 

 

 

요소의 비활성 readonly, disabled 차이와 사용법

 

reaonly 와 disabled는 보통 웹 페이지에서 어느 특정 요소를 비활성화 처리할 때 사용
(readonly는 text요소, 나머지 요소는 disabled 사용)

하지만 이 둘의 가장 큰 차이점은 DOM 객체에서 읽을 수 있느냐없느냐로
readonly의 경우 객체는 읽으나 객체의 쓰기를 비활성화하지만 disabled 된 요소는 DOM 객체를 아예 읽지 않는다. 

그러나 예외는 있다고 disabled 된 요소의 값을 간단히 서블릿으로 전달하는 2가지 방법이 있으며 아래와 같다.

1) hidden 으로 해당 값을 전달하는 방법으로 disabled된 요소의 값을 hidden된 input요소의 value 에 넣어 전달
2) submit이나 serialize 하기 전 해당 요소의 disabled 속성을 제거했다가 전송 후 다시 disabled  

 

$("#id").attr("disabled", false);  //해당 요소의 disabled 속성 변경(false)
var dataParam = $("#searchForm").serialize();  //데이터 serialize 
$("#id").attr("disabled", true);  //해당 요소의 disabled 속성 변경(true)

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
<select id="test" class="test" name="test">
    <option value="test1">1</option>
    <option value="test2">2</option>
    <option value="test3">3</option>
    <option value="test4">4</option>
</select>

 

이런 형식의 html에서 제이쿼리/자바스크립트로 선택한 요소의 값을 가져오려면
자바스크립트와 제이쿼리로는 각각 아래와 같이 가져오면 된다

 

var selectOption = document.getElementById("test");
selectOption = selectOption.options[selectOption.selectedIndex].value;
$("#test option:selected").val();

 

 

 

example : 글 목록 중 하나를 선택했을 때 가져오기

var list = $("#").val();
var option_values = document.getElementById("");
option_values = option_values.options[].value;
..

for(var j=0; j<option_values.length; j++){
	if(list == option_values[j]){
		할 것
        option_value[j].selected = true;
	} else {
		option_value[j].selected = false;
	}
}
728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

- val() :  input, select,textarea 등의 form elements에서 값을 구한다.

  .val(value) : form elements에 값을 지정한다.

- 값을 변경 할 때 : $(변경할 부분 선택).val(값);

  값을 가져 올 때 : $(변경할 부분 선택).val(값);


 

<html>
    <head>
        <title>게시판</title>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.js"></script>
        <script type="text/javascript">
            $(document).ready(function(){
            	
            	var reply_count = 0; //원래 DB에 저장하고 저장 아이디 번호를 넘겨줘야 하는데 DB 없이 댓글 소스만 있어 DB 에서 아이디 증가하는것처럼 스크립트에서 순번을 생성
            	var status = false; //수정과 대댓글을 동시에 적용 못하도록
                 
                $("#list").click(function(){
                	alert("게시판 리스트로 이동");
                    //location.href = "/board/list";
                });
                 
                //댓글 저장
                $("#reply_save").click(function(){
                     
                    //널 검사
                    if($("#reply_writer").val().trim() == ""){
                        alert("이름을 입력하세요.");
                        $("#reply_writer").focus();
                        return false;
                    }
                     
                    if($("#reply_password").val().trim() == ""){
                        alert("패스워드를 입력하세요.");
                        $("#reply_password").focus();
                        return false;
                    }
                     
                    if($("#reply_content").val().trim() == ""){
                        alert("내용을 입력하세요.");
                        $("#reply_content").focus();
                        return false;
                    }
                     
                    var reply_content = $("#reply_content").val().replace("\n", "<br>"); //개행처리
                     
                    //값 셋팅
                    var objParams = {
                            board_id        : $("#board_id").val(),
                            parent_id       : "0",  
                            depth           : "0",
                            reply_writer    : $("#reply_writer").val(),
                            reply_password  : $("#reply_password").val(),
                            reply_content   : reply_content
                    };
                     
                    var reply_id;
                     
                    //ajax 호출 (여기에 댓글을 저장하는 로직을 개발)
                    /*
                    $.ajax({
                        url         :   "/board/reply/save",
                        dataType    :   "json",
                        contentType :   "application/x-www-form-urlencoded; charset=UTF-8",
                        type        :   "post",
                        async       :   false, //동기: false, 비동기: ture
                        data        :   objParams,
                        success     :   function(retVal){
 
                            if(retVal.code != "OK") {
                                alert(retVal.message);
                            }else{
                                reply_id = retVal.reply_id;
                            }
                             
                        },
                        error       :   function(request, status, error){
                            console.log("AJAX_ERROR");
                        }
                    });
                    */
                    
                    
                    reply_id = reply_count++;//DB에 저장했다 하고 순번을 생성
                    
                    var reply_area = $("#reply_area");
                     
                    var reply = 
                        '<tr reply_type="main">'+
                        '   <td width="820px">'+
                        reply_content+
                        '   </td>'+
                        '   <td width="100px">'+
                        $("#reply_writer").val()+
                        '   </td>'+
                        '   <td width="100px">'+
                        '       <input type="password" id="reply_password_'+reply_id+'" style="width:100px;" maxlength="10" placeholder="패스워드"/>'+
                        '   </td>'+
                        '   <td align="center">'+
                        '       <button name="reply_reply" reply_id = "'+reply_id+'">댓글</button>'+
                        '       <button name="reply_modify" r_type = "main" reply_id = "'+reply_id+'">수정</button>      '+
                        '       <button name="reply_del" reply_id = "'+reply_id+'">삭제</button>      '+
                        '   </td>'+
                        '</tr>';
                         
                     if($('#reply_area').contents().size()==0){
                         $('#reply_area').append(reply);
                     }else{
                         $('#reply_area tr:last').after(reply);
                     }
 
                    //댓글 초기화
                    $("#reply_writer").val("");
                    $("#reply_password").val("");
                    $("#reply_content").val("");
                     
                });
                 
                //댓글 삭제
                $(document).on("click","button[name='reply_del']", function(){
                     
                    var check = false;
                    var reply_id = $(this).attr("reply_id");
                    var reply_password = "reply_password_"+reply_id;
                     
                    if($("#"+reply_password).val().trim() == ""){
                        alert("패스워드을 입력하세요.");
                        $("#"+reply_password).focus();
                        return false;
                    }
                     
                    //패스워드와 아이디를 넘겨 삭제를 한다.
                    //값 셋팅
                    var objParams = {
                            reply_password  : $("#"+reply_password).val(),
                            reply_id        : reply_id
                    };
                     
                    //ajax 호출
                    /*
                    $.ajax({
                        url         :   "/board/reply/del",
                        dataType    :   "json",
                        contentType :   "application/x-www-form-urlencoded; charset=UTF-8",
                        type        :   "post",
                        async       :   false, //동기: false, 비동기: ture
                        data        :   objParams,
                        success     :   function(retVal){
 
                            if(retVal.code != "OK") {
                                alert(retVal.message);
                            }else{
                                 
                                check = true;
                                                                 
                            }
                             
                        },
                        error       :   function(request, status, error){
                            console.log("AJAX_ERROR");
                        }
                    });
                    */
                    
                    check = true;//삭제 되면 체크값을 true로 변경
                     
                    if(check){
                        //삭제하면서 하위 댓글도 삭제
                        var prevTr = $(this).parent().parent().next(); //댓글의 다음
                         
                        while(prevTr.attr("reply_type")=="sub"){//댓글의 다음이 sub면 계속 넘어감
                            prevTr = prevTr.next();
                            prevTr.prev().remove();
                        }
                         
                        //마지막 리플 처리
                        if(prevTr.attr("reply_type") == undefined){
                            prevTr = $(this).parent().parent();
                            prevTr.remove();
                        }
                         
                        $(this).parent().parent().remove(); 
                    }
                     
                });
                
                //댓글 수정 입력
                $(document).on("click","button[name='reply_modify']", function(){
                	
                    var check = false;
                    var reply_id = $(this).attr("reply_id");
                    var r_type = $(this).attr("r_type");
                    var reply_password = "reply_password_"+reply_id;
                     
                    if($("#"+reply_password).val().trim() == ""){
                        alert("패스워드을 입력하세요.");
                        $("#"+reply_password).focus();
                        return false;
                    }
                     
                    //패스워드와 아이디를 넘겨 패스워드 확인
                    //값 셋팅
                    var objParams = {
                            reply_password  : $("#"+reply_password).val(),
                            reply_id        : reply_id
                    };
                     
                    //ajax 호출
                    /*
                    $.ajax({
                        url         :   "/board/reply/check",
                        dataType    :   "json",
                        contentType :   "application/x-www-form-urlencoded; charset=UTF-8",
                        type        :   "post",
                        async       :   false, //동기: false, 비동기: ture
                        data        :   objParams,
                        success     :   function(retVal){
 
                            if(retVal.code != "OK") {
                                alert(retVal.message);
                            }else{
                                 
                                check = true;
                                                                 
                            }
                             
                        },
                        error       :   function(request, status, error){
                            console.log("AJAX_ERROR");
                        }
                    });
                    */
                    
                    check = true;//패스워드가 맞으면 체크값을 true로 변경
                    
                    if(status){
                		alert("수정과 대댓글은 동시에 불가합니다.");
                		return false;
                	}
                	
                	status = true;
                    
                    if(check){
                    	//자기 위에 댓글 수정창 입력하고 기존값을 채우고 자기 자신 삭제
                    	var txt_reply_content = $(this).parent().prev().prev().prev().html().trim(); //댓글내용 가져오기
                    	if(r_type=="sub"){
                    		txt_reply_content = txt_reply_content.replace("→ ","");//대댓글의 뎁스표시(화살표) 없애기
                    	}
                    	
                    	var txt_reply_writer = $(this).parent().prev().prev().html().trim(); //댓글작성자 가져오기
                    	
                    	//입력받는 창 등록
                        var replyEditor = 
                           '<tr id="reply_add" class="reply_modify">'+
                           '   <td width="820px">'+
                           '       <textarea name="reply_modify_content_'+reply_id+'" id="reply_modify_content_'+reply_id+'" rows="3" cols="50">'+txt_reply_content+'</textarea>'+ //기존 내용 넣기
                           '   </td>'+
                           '   <td width="100px">'+
                           '       <input type="text" name="reply_modify_writer_'+reply_id+'" id="reply_modify_writer_'+reply_id+'" style="width:100%;" maxlength="10" placeholder="작성자" value="'+txt_reply_writer+'"/>'+ //기존 작성자 넣기
                           '   </td>'+
                           '   <td width="100px">'+
                           '       <input type="password" name="reply_modify_password_'+reply_id+'" id="reply_modify_password_'+reply_id+'" style="width:100%;" maxlength="10" placeholder="패스워드"/>'+
                           '   </td>'+
                           '   <td align="center">'+
                           '       <button name="reply_modify_save" r_type = "'+r_type+'" reply_id="'+reply_id+'">등록</button>'+
                           '       <button name="reply_modify_cancel" r_type = "'+r_type+'" r_content = "'+txt_reply_content+'" r_writer = "'+txt_reply_writer+'" reply_id="'+reply_id+'">취소</button>'+
                           '   </td>'+
                           '</tr>';
                        var prevTr = $(this).parent().parent();
                       	//자기 위에 붙이기
                        prevTr.after(replyEditor);
                        
                        //자기 자신 삭제
                        $(this).parent().parent().remove(); 
                    }
                     
                });
                //댓글 수정 취소
                $(document).on("click","button[name='reply_modify_cancel']", function(){
                	//원래 데이터를 가져온다.
                	var r_type = $(this).attr("r_type");
                	var r_content = $(this).attr("r_content");
                	var r_writer = $(this).attr("r_writer");
                	var reply_id = $(this).attr("reply_id");
                	
                	var reply;
                	//자기 위에 기존 댓글 적고 
                	if(r_type=="main"){
                		reply = 
                            '<tr reply_type="main">'+
                            '   <td width="820px">'+
                            r_content+
                            '   </td>'+
                            '   <td width="100px">'+
                            r_writer+
                            '   </td>'+
                            '   <td width="100px">'+
                            '       <input type="password" id="reply_password_'+reply_id+'" style="width:100px;" maxlength="10" placeholder="패스워드"/>'+
                            '   </td>'+
                            '   <td align="center">'+
                            '       <button name="reply_reply" reply_id = "'+reply_id+'">댓글</button>'+
                            '       <button name="reply_modify" r_type = "main" reply_id = "'+reply_id+'">수정</button>      '+
                            '       <button name="reply_del" reply_id = "'+reply_id+'">삭제</button>      '+
                            '   </td>'+
                            '</tr>';
                	}else{
                		reply = 
                            '<tr reply_type="sub">'+
                            '   <td width="820px"> → '+
                            r_content+
                            '   </td>'+
                            '   <td width="100px">'+
                            r_writer+
                            '   </td>'+
                            '   <td width="100px">'+
                            '       <input type="password" id="reply_password_'+reply_id+'" style="width:100px;" maxlength="10" placeholder="패스워드"/>'+
                            '   </td>'+
                            '   <td align="center">'+
                            '       <button name="reply_modify" r_type = "sub" reply_id = "'+reply_id+'">수정</button>'+
                            '       <button name="reply_del" reply_id = "'+reply_id+'">삭제</button>'+
                            '   </td>'+
                            '</tr>';
                	}
                	
                	var prevTr = $(this).parent().parent();
                   	//자기 위에 붙이기
                    prevTr.after(reply);
                   	
                  	//자기 자신 삭제
                    $(this).parent().parent().remove(); 
                  	
                    status = false;
                	
                });
                
              	//댓글 수정 저장
                $(document).on("click","button[name='reply_modify_save']", function(){
                	
                	var reply_id = $(this).attr("reply_id");
                	
                	//널 체크
                    if($("#reply_modify_writer_"+reply_id).val().trim() == ""){
                        alert("이름을 입력하세요.");
                        $("#reply_modify_writer_"+reply_id).focus();
                        return false;
                    }
                     
                    if($("#reply_modify_password_"+reply_id).val().trim() == ""){
                        alert("패스워드를 입력하세요.");
                        $("#reply_modify_password_"+reply_id).focus();
                        return false;
                    }
                     
                    if($("#reply_modify_content_"+reply_id).val().trim() == ""){
                        alert("내용을 입력하세요.");
                        $("#reply_modify_content_"+reply_id).focus();
                        return false;
                    }
                	//DB에 업데이트 하고
                	//ajax 호출 (여기에 댓글을 저장하는 로직을 개발)
                	var reply_content = $("#reply_modify_content_"+reply_id).val().replace("\n", "<br>"); //개행처리
                    
                	var r_type = $(this).attr("r_type");
                	
                	var parent_id;
                	var depth;
                	if(r_type=="main"){
                		parent_id = "0";
                		depth = "0";
                	}else{
                		parent_id = $(this).attr("reply_id");
                		depth = "1";
                	}
                	
                    //값 셋팅
                    var objParams = {
                            board_id        : $("#board_id").val(),
                            parent_id       : parent_id, 
                            depth           : depth,
                            reply_writer    : $("#reply_modify_writer_"+reply_id).val(),
                            reply_password  : $("#reply_modify_password_"+reply_id).val(),
                            reply_content   : reply_content
                    };
                    /*
                    $.ajax({
                        url         :   "/board/reply/update",
                        dataType    :   "json",
                        contentType :   "application/x-www-form-urlencoded; charset=UTF-8",
                        type        :   "post",
                        async       :   false, //동기: false, 비동기: ture
                        data        :   objParams,
                        success     :   function(retVal){
 
                            if(retVal.code != "OK") {
                                alert(retVal.message);
                            }else{
                                reply_id = retVal.reply_id;
                            }
                             
                        },
                        error       :   function(request, status, error){
                            console.log("AJAX_ERROR");
                        }
                    });
                    */
                	//수정된댓글 내용을 적고
                    if(r_type=="main"){
                		reply = 
                            '<tr reply_type="main">'+
                            '   <td width="820px">'+
                            $("#reply_modify_content_"+reply_id).val()+
                            '   </td>'+
                            '   <td width="100px">'+
                            $("#reply_modify_writer_"+reply_id).val()+
                            '   </td>'+
                            '   <td width="100px">'+
                            '       <input type="password" id="reply_password_'+reply_id+'" style="width:100px;" maxlength="10" placeholder="패스워드"/>'+
                            '   </td>'+
                            '   <td align="center">'+
                            '       <button name="reply_reply" reply_id = "'+reply_id+'">댓글</button>'+
                            '       <button name="reply_modify" r_type = "main" reply_id = "'+reply_id+'">수정</button>      '+
                            '       <button name="reply_del" reply_id = "'+reply_id+'">삭제</button>      '+
                            '   </td>'+
                            '</tr>';
                	}else{
                		reply = 
                            '<tr reply_type="sub">'+
                            '   <td width="820px"> → '+
                            $("#reply_modify_content_"+reply_id).val()+
                            '   </td>'+
                            '   <td width="100px">'+
                            $("#reply_modify_writer_"+reply_id).val()+
                            '   </td>'+
                            '   <td width="100px">'+
                            '       <input type="password" id="reply_password_'+reply_id+'" style="width:100px;" maxlength="10" placeholder="패스워드"/>'+
                            '   </td>'+
                            '   <td align="center">'+
                            '       <button name="reply_modify" r_type = "sub" reply_id = "'+reply_id+'">수정</button>'+
                            '       <button name="reply_del" reply_id = "'+reply_id+'">삭제</button>'+
                            '   </td>'+
                            '</tr>';
                	}
                    
                    var prevTr = $(this).parent().parent();
                   	//자기 위에 붙이기
                    prevTr.after(reply);
                   	
                  	//자기 자신 삭제
                    $(this).parent().parent().remove(); 
                  	
                    status = false;
                	
                });
                 
                //대댓글 입력창
                $(document).on("click","button[name='reply_reply']",function(){ //동적 이벤트
                	
                	if(status){
                		alert("수정과 대댓글은 동시에 불가합니다.");
                		return false;
                	}
                	
                	status = true;
                     
                    $("#reply_add").remove();
                     
                    var reply_id = $(this).attr("reply_id");
                    var last_check = false;//마지막 tr 체크
                     
                    //입력받는 창 등록
                    var replyEditor = 
                       '<tr id="reply_add" class="reply_reply">'+
                       '   <td width="820px">'+
                       '       <textarea name="reply_reply_content" rows="3" cols="50"></textarea>'+
                       '   </td>'+
                       '   <td width="100px">'+
                       '       <input type="text" name="reply_reply_writer" style="width:100%;" maxlength="10" placeholder="작성자"/>'+
                       '   </td>'+
                       '   <td width="100px">'+
                       '       <input type="password" name="reply_reply_password" style="width:100%;" maxlength="10" placeholder="패스워드"/>'+
                       '   </td>'+
                       '   <td align="center">'+
                       '       <button name="reply_reply_save" reply_id="'+reply_id+'">등록</button>'+
                       '       <button name="reply_reply_cancel">취소</button>'+
                       '   </td>'+
                       '</tr>';
                         
                    var prevTr = $(this).parent().parent().next();
                     
                    //부모의 부모 다음이 sub이면 마지막 sub 뒤에 붙인다.
                    //마지막 리플 처리
                    if(prevTr.attr("reply_type") == undefined){
                        prevTr = $(this).parent().parent();
                    }else{
                        while(prevTr.attr("reply_type")=="sub"){//댓글의 다음이 sub면 계속 넘어감
                            prevTr = prevTr.next();
                        }
                         
                        if(prevTr.attr("reply_type") == undefined){//next뒤에 tr이 없다면 마지막이라는 표시를 해주자
                            last_check = true;
                        }else{
                            prevTr = prevTr.prev();
                        }
                         
                    }
                     
                    if(last_check){//마지막이라면 제일 마지막 tr 뒤에 댓글 입력을 붙인다.
                        $('#reply_area tr:last').after(replyEditor);    
                    }else{
                        prevTr.after(replyEditor);
                    }
                     
                });
                 
                //대댓글 등록
                $(document).on("click","button[name='reply_reply_save']",function(){
                                         
                    var reply_reply_writer = $("input[name='reply_reply_writer']");
                    var reply_reply_password = $("input[name='reply_reply_password']");
                    var reply_reply_content = $("textarea[name='reply_reply_content']");
                    var reply_reply_content_val = reply_reply_content.val().replace("\n", "<br>"); //개행처리
                     
                    //널 검사
                    if(reply_reply_writer.val().trim() == ""){
                        alert("이름을 입력하세요.");
                        reply_reply_writer.focus();
                        return false;
                    }
                     
                    if(reply_reply_password.val().trim() == ""){
                        alert("패스워드를 입력하세요.");
                        reply_reply_password.focus();
                        return false;
                    }
                     
                    if(reply_reply_content.val().trim() == ""){
                        alert("내용을 입력하세요.");
                        reply_reply_content.focus();
                        return false;
                    }
                     
                    //값 셋팅
                    var objParams = {
                            board_id        : $("#board_id").val(),
                            parent_id       : $(this).attr("reply_id"), 
                            depth           : "1",
                            reply_writer    : reply_reply_writer.val(),
                            reply_password  : reply_reply_password.val(),
                            reply_content   : reply_reply_content_val
                    };
                     
                    var reply_id;
                     
                    //ajax 호출
                    /*
                    $.ajax({
                        url         :   "/board/reply/save",
                        dataType    :   "json",
                        contentType :   "application/x-www-form-urlencoded; charset=UTF-8",
                        type        :   "post",
                        async       :   false, //동기: false, 비동기: ture
                        data        :   objParams,
                        success     :   function(retVal){
 
                            if(retVal.code != "OK") {
                                alert(retVal.message);
                            }else{
                                reply_id = retVal.reply_id;
                            }
                             
                        },
                        error       :   function(request, status, error){
                            console.log("AJAX_ERROR");
                        }
                    });
                    */
                    
                    reply_id = reply_count++;//DB에 저장했다 하고 순번을 생성
                     
                    var reply = 
                        '<tr reply_type="sub">'+
                        '   <td width="820px"> → '+
                        reply_reply_content_val+
                        '   </td>'+
                        '   <td width="100px">'+
                        reply_reply_writer.val()+
                        '   </td>'+
                        '   <td width="100px">'+
                        '       <input type="password" id="reply_password_'+reply_id+'" style="width:100px;" maxlength="10" placeholder="패스워드"/>'+
                        '   </td>'+
                        '   <td align="center">'+
                        '       <button name="reply_modify" r_type = "sub" reply_id = "'+reply_id+'">수정</button>'+
                        '       <button name="reply_del" reply_id = "'+reply_id+'">삭제</button>'+
                        '   </td>'+
                        '</tr>';
                         
                    var prevTr = $(this).parent().parent().prev();
                     
                    prevTr.after(reply);
                                         
                    $("#reply_add").remove();
                    
                    status = false;
                     
                });
                 
                //대댓글 입력창 취소
                $(document).on("click","button[name='reply_reply_cancel']",function(){
                    $("#reply_add").remove();
                    
                    status = false;
                });
                 
                //글수정
                $("#modify").click(function(){
                     
                    var password = $("input[name='password']");
                     
                    if(password.val().trim() == ""){
                        alert("패스워드를 입력하세요.");
                        password.focus();
                        return false;
                    }
                                         
                    //ajax로 패스워드 검수 후 수정 페이지로 포워딩
                    //값 셋팅
                    var objParams = {
                            id       : $("#board_id").val(),    
                            password : $("#password").val()
                    };
                                         
                    //ajax 호출
                   	alert("패스워드 체크하고 맞으면 수정페이지로 이동");
                    /*
                    $.ajax({
                        url         :   "/board/check",
                        dataType    :   "json",
                        contentType :   "application/x-www-form-urlencoded; charset=UTF-8",
                        type        :   "post",
                        async       :   false, //동기: false, 비동기: ture
                        data        :   objParams,
                        success     :   function(retVal){
 
                            if(retVal.code != "OK") {
                                alert(retVal.message);
                            }else{
                                location.href = "/board/edit?id="+$("#board_id").val();
                            }
                             
                        },
                        error       :   function(request, status, error){
                            console.log("AJAX_ERROR");
                        }
                    });
                    */
                     
                });
                 
                //글 삭제
                $("#delete").click(function(){
                     
                    var password = $("input[name='password']");
                     
                    if(password.val().trim() == ""){
                        alert("패스워드를 입력하세요.");
                        password.focus();
                        return false;
                    }
                     
                    //ajax로 패스워드 검수 후 수정 페이지로 포워딩
                    //값 셋팅
                    var objParams = {
                            id       : $("#board_id").val(),    
                            password : $("#password").val()
                    };
                    
                    alert("패스워드 체크하고 맞으면 게시글 삭제후 리스트 페이지 이동");
                    /*                 
                    //ajax 호출
                    $.ajax({
                        url         :   "/board/del",
                        dataType    :   "json",
                        contentType :   "application/x-www-form-urlencoded; charset=UTF-8",
                        type        :   "post",
                        async       :   false, //동기: false, 비동기: ture
                        data        :   objParams,
                        success     :   function(retVal){
 
                            if(retVal.code != "OK") {
                                alert(retVal.message);
                            }else{
                                alert("삭제 되었습니다.");
                                location.href = "/board/list";
                            }
                             
                        },
                        error       :   function(request, status, error){
                            console.log("AJAX_ERROR");
                        }
                    });
                    */
                     
                });
                 
            });
        </script>
    </head>
    <style>
        textarea{
              width:100%;
            }
             
        .reply_reply {
                border: 2px solid #FF50CF;
            }
        .reply_modify {
                border: 2px solid #FFBB00;
            }
    </style>
    <body>
        <input type="hidden" id="board_id" name="board_id" value="${boardView.id}" />
        <div align="center">
            </br>
            </br>
            <table border="1" width="1200px" >
                <tr>
                    <td colspan="2" align="right">
                        <input type="password" id="password" name="password" style="width:200px;" maxlength="10" placeholder="패스워드"/>
                        <button id="modify" name="modify">글 수정</button>
                        <button id="delete" name="delete">글 삭제</button>
                    </td>
                </tr>
                <tr>
                    <td width="900px">
                        제목: 댓글 테스트
                    </td>
                    <td>
                        작성자: 허스크
                    </td>
                </tr>
                <tr height="200px">
                    <td colspan="2" valign="top">
                        게시글 내용
                    </td>
                </tr>
            </table>
            <table border="1" width="1200px" id="reply_area">
                <tr reply_type="all"><!-- 뒤에 댓글 붙이기 쉽게 선언 -->
                    <td colspan="4"></td>
                </tr>
                <!-- 댓글이 들어갈 공간 -->
            </table>
            <table border="1" width="1200px" bordercolor="#46AA46">
                <tr>
                    <td width="500px">
                        이름: <input type="text" id="reply_writer" name="reply_writer" style="width:170px;" maxlength="10" placeholder="작성자"/>
                        패스워드: <input type="password" id="reply_password" name="reply_password" style="width:170px;" maxlength="10" placeholder="패스워드"/>
                        <button id="reply_save" name="reply_save">댓글 등록</button>
                    </td>
                </tr>
                <tr>
                    <td>
                        <textarea id="reply_content" name="reply_content" rows="4" cols="50" placeholder="댓글을 입력하세요."></textarea>
                    </td>
                </tr>
            </table>
            <table width="1200px">
                <tr>
                    <td align="right">
                        <button id="list" name="list">게시판</button>
                    </td>
                </tr>
            </table>
        </div>
    </body>
</html>

 

 

 

 

 

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

 

 

01 클로저의 의미 및 원리 이해

 

클로저 closure :

여러 함수형 프로그래밍 언어에서 등장하는 보편적인 특성으로 자바스크립트 고유의 개념이 아니라서 ECMAScript 명세에서도 정의를 다루지 않고 있고 문헌마다 다양하게 정의, 설명하고 있으며 문장도 모호하다. 그러나 반대로 잘 잡으면 이해하기 쉬운 개념이 클로저

문헌들에서는 자신을 내포하는 함수의 컨텍스트에 접근할 수 있는 함수, 특정 스코프에 접근할 수 있도록 의도적으로 스코프에서 함수를 정의하기, 함수를 선언할 때 만들어지는 유효범위가 사라진 후에도 호출할 수 있는 함수, 이미 생명 주기상 끝난 외부 함수의 변수를 참조하는 함수, 로컬 변수를 참조하고 있는 함수 내의 함수 등등으로 얘기한다.

 

함수를 둘러싼 환경이라는 것이 렉시컬 스코프이다.
함수를 만들고 그 함수 내부의 코드가 탐색하는 스코프를 함수 생성 당시의 렉시컬 스코프로 고정하면 바로 클로저가 되는 것이다.

 

 

클로저란 "어떤 함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상"

MDN (Mozilla Developer Network) 에서는 클로저를 'the combination of a function and the lexical environment within which that function was declared' 라고 한다. 즉, 함수와 함수가 선언될 당시의 lexical environment의 상호관계에 따른 현상인 것이다.
선언 당시의 lexical environment는 2장에 나온 실행컨텍스트의 구성 요소 중 하나인 outerEnvironmentReference에 해당

LexicalEnvironment의 environmentRecordouterEnvironmentReference에 의해
변수의 유효범위인 스코프가 결정되고 스코프체인이 가능해진다.

# 어떤 컨텍스트 A에서 선언한 내부함수 B의 실행컨텍스트가 활성화된 시점에는
B의 outerEnvironmentReference가 참조하는 대상인 A의 LexicalEnvironment에도 접근이 가능하고
A에서는 B에서 선언한 변수에 접근할 수 없지만 반대로는 가능한데,
내부함수 B가 A의 LexicalEnvironment를 언제나 사용하진 않고
그럴 경우 combination이라 할 수 없다

즉 선언 당시의 LecxicalEnvironment와의 상호관계가 의미가 있다

 

이제 외부 함수의 변수를 참조하는 내부 함수의 4가지 예시로 살펴보겠습니다.

 

5-1

var outer = function() {
	var a = 1;
	var inner = function() {
		console.log(++a);  // 2 출력
	// a를 선언하지 않아 environmentRecord에서 값을 못찾아서
	// LexicalEnvironment에 접근해 다시 a를 찾는다
	};
	inner();
);
outer(); 
// 실행 컨텍스트가 종료되면 LexicalEnvironment에 저장된
// 식별자 (a, inner) 에 대한 참조를 지운다
// 이제 각 주소에 저장된 값들은 참조당하는 변수가 없어서 
// 언젠가 가비지컬렉터에 수거가 될 것이다

 

5-2

var outer = function() {
	var a = 1;
    
	var inner = function() {
		return ++a;  // 외부변수 a 사용
	};
	return inner(); // inner함수의 실행결과 리턴
};

var outer2 = outer();  
console.log(outer2); // 2이지만 예제는 실행되지 않았다...
// outer함수의 실행컨텍스트가 종료된 시점에는 a변수를 참조하는 대상의 소멸
// 가비지컬렉터에 의해 소멸되며 일반적 함수, 내부함수의 동작과 같다

 

5-1, 5-2는 outer 함수의 실행컨텍스트가 종료되기 이전에 inner 함수의 실행컨텍스트가 종료되며 이후 별도로 inner 함수를 호출 할 수 없는 예제이고 5-3은 outer 함수의 실행컨텍스트가 종료 이후 inner 함수를 호출할 수 있게 만든 예제입니다.

 

5-3

var outer = function() {
	var a = 1;
    
	var inner = function() {
		return ++a;  
	};
	return inner; 
    // 실행결과가 아닌 함수 자체를 반환
};

var outer2 = outer();  
console.log(outer2()); //2 
console.log(outer2()); //3

 

inner  함수의 실행컨텍스트의 environmentRecord에는 수집할 정보가 없으며
outer-environmentReference에는 inner 함수가 선언된 위치의 LexicalEnvironment가 참조 복사되며
inner 함수는 outer 함수 내부에서 선언되어 outer 함수의 LexicalEnvironment가 담기고
스코프 체이닝에 따라 outer 에서 선언한 변수 a 에 접근해서 증가시킨 후 2를 반환하고 inner 함수의 실행컨텍스트가 종료된다
다시 마지막에서 outer2를 호출하면 a를 다시 증가시키고 3을 반환한다

inner 함수의 실행시점에는  outer 함수가 실행종료됐는데 outer 함수의 LexicalEnvironment에 접근할 수 있는 이유는
어떤 값을 참조하는 변수가 하나라도 있으면 수집대상이 니게 되는 가비지컬렉터의 동작 특성 때문
즉 예제
1,2와 다르게 outer 외부함수의 실행이 종료되도 내부함수인 inner 함수는 언젠가 outer2를 호출해 실행할 가능성이 예측되며
inner 함수의 실행 컨텍스트가 활성화되면 outerEnvironmentReference가 outer 함수의 LexicalEnvironment를 필요로 할 것이기 때문
그래서 inner 함수가 변수에 접근 가능한 것

= 클로저는 어떤 함수에서 선언한 내부 함수에서만 발생하는 현상이자
유일하게 함수의 실행컨텍스트가 종료된 후에도 외부함수의 LexicalEnvironment가 가비지컬렉팅되지 않는 현상

 

외부로의 전달은 return 없이도 가능하다

 

(function() {
	var a = 0;
	var intervalId = null;
	var inner = function(){
		if(++a>=10){
			clearInterval(intervalId);
		}
		console.log(a);  // 1 2 3 4 ... 10
	};
	intervalId = setInterval(inner, 1000);
})();

 

즉시실행함수의 예인데 별도의 외부객체인 window의 메서드에 전달할 콜백함수 내부에서 지역변수를 참조한다
지역변수를 참조하는 내부함수를 외부에 전달했기에 클로저라 할 수 있다

 

더보기
var color = 'red';
function foo() {
    var color = 'blue'; // 2
    function bar() {
        console.log(color); // 1
    }
    return bar;
}
var baz = foo(); // 3
baz(); // 4
  1. bar는 color를 찾아 출력하는 함수로 정의되었다.
  2. 그리고 bar는 outer environment 참조로 foo의 environment를 저장하였다.
  3. bar를 global의 baz란 이름으로 데려왔다.
  4. global에서 baz(=bar)를 호출했다.
  5. bar는 자신의 스코프에서 color를 찾는다.
  6. 없다. 자신의 outer environment 참조를 찾아간다.
  7. outer environment인 foo의 스코프를 뒤진다. color를 찾았다. 값은 blue이다.
  8. 때문에 당연히 blue가 출력된다.

이런 bar(또는 baz)와 같은 함수를 우리는 클로저라고 부른다. 
baz bar로 초기화할 때는 이미 bar outer lexical environment foo로 결정한 이후이다. 
때문에, 
bar의 생성과 직접적인 관련이 없는 global에서 아무리 호출하더라도 여전히 foo에서 color를 찾는 것이다. 

foo의 렉시컬환경 인스턴스는 foo(); 수행이 끝난 이후 GC가 회수해야 하는데 사실을 그렇지 않다. 
bar는 여전히 바깥 렉시컬 환경인 foo의 렉시컬 환경을 계속 참조하고 있고,
 
bar baz가 여전히 참조하고 있기 때문이다.(baz(=bar) -> foo)

 

 

 

 

 

 

02 클로저와 메모리 관리

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

Text Node의 Value 바꾸기

 

nodeValue의 property는 textnode의 value를 바꾸는 데 사용된다

 

nodeValue : Node interface의 nodeValue property는 현재 노드(current node)의 값(value)을 반환(return)하거나 설정한다 >>참고

document 자기자신을 가리키면 nodeValue는 null을 반환한다
text, comment, CDATA nodes는 node의 내용을 반환한다
attribute 노드는 attribute 값을 반환한다

 

 

예시

<!DOCTYPE html>
<html>
<body>

<p id="demo"></p>

<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        myFunction(this);
    }
};
xhttp.open("GET", "books.xml", true);
xhttp.send();

function myFunction(xml) {
    var xmlDoc = xml.responseXML;
    var x;    
    var txt = "";
    x = xmlDoc.getElementsByTagName("title")[0].childNodes[0];
    txt += x.nodeValue + "<br>";    
    x.nodeValue = "Easy Cooking";
    
    // 바꾸는 부분
    x = xmlDoc.getElementsByTagName("title")[0].childNodes[0];
    txt += x.nodeValue + "<br>";    
    document.getElementById("demo").innerHTML = txt;
}
// https://www.w3schools.com/xml/tryit.asp?filename=try_dom_change_nodevalue
</script>
</body>
</html>
<!-- books.xml -->
<bookstore>
   <book category="cooking">
       <title lang="en">Everyday Italian</title>
       <author>Giada De Laurentiis</author>
       <year>2005</year>
       <price>30.00</price> </book>
   <book category="children">
       <title lang="en">Harry Potter</title>
       <author>J K. Rowling</author>
       <year>2005</year>
       <price>29.99</price> </book>
   <book category="web">
       <title lang="en">XQuery Kick Start</title>
       <author>James McGovern</author>
       <author>Per Bothner</author>
       <author>Kurt Cagle</author>
       <author>James Linn</author>
       <author>Vaidyanathan Nagarajan</author>
       <year>2003</year>
       <price>49.99</price> </book>
   <book category="web" cover="paperback">
       <title lang="en">Learning XML</title>
       <author>Erik T. Ray</author>
       <year>2003</year>
       <price>39.95</price> </book>
</bookstore>

 

 

 

 

Attribute의 Value 바꾸기

DOM에서 attribute 들은 여러 개의 노드이다. 요소 (element) 노드와 달리 attribute 노드에는 텍스트 값이 있다.
속성 값을 변경하는 방법은 텍스트 값을 변경하는 것이다. setAttribute () 메소드를 사용해서 변경하거나, attribute 노드의 nodeValue 프로퍼티를 설정하여 변경한다.

 

1) setAttribute() 이용

 

<!DOCTYPE html>
<html>
<body>

<p id="demo"></p>

<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        myFunction(this);
    }
};
xhttp.open("GET", "books.xml", true);
xhttp.send();

function myFunction(xml) {
    var xmlDoc = xml.responseXML;
    var x = xmlDoc.getElementsByTagName('book');
    x[0].setAttribute("category","food"); //원래 값은 cooking
    document.getElementById("demo").innerHTML =
    x[0].getAttribute("category");
}
// https://www.w3schools.com/xml/tryit.asp?filename=try_dom_setattribute1
</script>

</body>
</html>


 

 

2) nodeValue() 이용

 

<!DOCTYPE html>
<html>
<body>

<p id="demo"></p>

<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        myFunction(this);
    }
};
xhttp.open("GET", "books.xml", true);
xhttp.send();

function myFunction(xml) {
    var xmlDoc = xml.responseXML;
    var x = xmlDoc.getElementsByTagName("book")[0]
    var y = x.getAttributeNode("category");
    
    var txt = y.nodeValue + "<br>";
    y.nodeValue ="food";
    txt += y.nodeValue;
    document.getElementById("demo").innerHTML = txt;
}
</script>
</body>
</html>
728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

부트스트랩 웹사이트 바로가기

 

 

Modal

Use Bootstrap’s JavaScript modal plugin to add dialogs to your site for lightboxes, user notifications, or completely custom content.

getbootstrap.com

 

 


 

Bootstrap의 모달 컴포넌트를 시작하기 전에...

* 메뉴 옵션이 최근 변경됨 *

  • 모달은 HTML, CSS 및 JavaScript로 빌드됩니다. 그것들은 문서의 다른 모든 것 위에 <body>위치하고 모달 내용이 대신 스크롤되도록 스크롤을 제거 합니다.
  • 모달“배경”을 클릭하면 모달이 자동으로 닫힙니다. (안닫히는 버전도 있음)
  • 부트 스트랩은 한 번에 하나의 모달 창만 지원합니다. 중첩 된 모달은 사용자 경험이 좋지 않다고 믿기 때문에 지원되지 않습니다.
  • 모달은을 사용하는데 position: fixed, 렌더링에 약간 특별한 경우가 있습니다. 가능하면 모달 HTML을 최상위 위치에 두어 다른 요소의 잠재적 인 간섭을 피하십시오. .modal다른 고정 요소 내에 중첩하면 문제가 발생할 수 있습니다.
  • 다시 한 번으로 인해 position: fixed휴대 기기에서 모달을 사용할 때주의해야 할 사항이 있습니다. 자세한 내용은 브라우저 지원 문서 를 참조하십시오.
  • 때문에 방법은 HTML5를 정의의 의미로, HTML 속성은 부트 스트랩 조동사에 영향을주지 않습니다. 동일한 효과를 얻으려면 몇 가지 사용자 정의 JavaScript를 사용하십시오.autofocus

 

https://m.blog.naver.com/PostView.nhn?blogId=hcege&logNo=220850816503&proxyReferer=https%3A%2F%2Fwww.google.com%2F

https://m.blog.naver.com/PostView.nhn?blogId=hcege&logNo=220850816503&proxyReferer=https%3A%2F%2Fwww.google.com%2F

 

 

 

JavaScript를 작성하지 않고 모달을 활성화

 

<button type="button" data-toggle="modal" data-target="#myModal">Launch modal</button>

 

 

 

JavaScript로 모달을 활성화

 

$('#myModal').modal(options)

 

 

 

 

창 외부를 클릭하면 자동으로 닫히는 모달

 

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
  Launch demo modal
</button>

<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

 

 

 

닫기 버튼을 클릭하면 닫히는 모달

 

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdrop">
  Launch static backdrop modal
</button>

<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Understood</button>
      </div>
    </div>
  </div>
</div>

 

 

모달 팝업창 크기 

 

작은 .modal-sm 300px
기본 없음 500px
.modal-lg 800px
특대 .modal-xl 1140px

 

 

 

모달 팝업창 위에 다른 모달 팝업 띄우기

 

div를 사용할 경우 z-index 값을 다르게 한 modal 인스턴스를 하나 더 선언, 호출해서 사용하면 됩니다.
꼭 아래 배경이 유지되어야 할 필요성이 없을 때는 기존 모달 팝업을 닫히게 한 후 같은 위치에 띄우고, 새로운 모달 팝업 창을 닫았을 때 다시 기존 팝업창을 부활시켜도 되겠습니다.

 

1번 : z-indx 값이 1060 최상단 위치

2번 : z-indx 값이 1050 중간 위치

3번 : z-indx 값이 1041 마지막 위치

 

 


 

툴팁이란?

 

 

Tooltips

Documentation and examples for adding custom Bootstrap tooltips with CSS and JavaScript using CSS3 for animations and data-attributes for local title storage.

getbootstrap.com

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

인라인 방식

 

inline 방식은 태그에 직접 자바스크립트를 기술하는 방식이다. 장점은 태그에 연관된 스크립트가 분명하게 드러난다는 점이다. 하지만 정보와 제어가 섞여 있기 때문에 정보로서의 가치가 떨어진다.

 

<input type="button" onclick="alert('Hello world')" value="Hello world" />

 

 

 

인라인 코드에서 분리하는 방법

 

<script></script> 태그를 만들어서 여기에 자바스크립트 코드를 삽입하는 방식이다.
장점은 html 태그와 js 코드를 분리할 수 있다

 

<input type="button" id="hw" value="Hello world" />

<script type="text/javascript">
  var hw = document.getElementById('hw');
  
  hw.addEventListener('click', function(){
  	alert('Hello world');
  })
</script>

 

js를 별도의 외부 파일로 분리해서도 가능하겠다. 장점은 보다 엄격하게 정보와 제어를 분리할 수 있다. 하나의 js 파일을 여러 웹페이지에서 로드함으로서 js의 재활용성을 높일 수 있으며 캐쉬를 통해서 속도의 향상, 전송량의 경량화를 도모할 수 있다. Script 파일의 위치는 head 태그 사이에 위치할 경우 오류가 발생할 수도 있다. body 태그 하단쪽에 넣거나 window.onload = function(){} 함수로 모든 구성요소에 대한 로드가 끝났을 때 브라우저에 의해서 호출되게 해야할 것이다.

 

 

 

 

[JavaScript] 이벤트 핸들러

자바 스크립트에서 이벤트 핸들러를 등록하는 방법은 세 가지가 있다.​1. HTML 요소의 속성으로 등록...

blog.naver.com

 

20. 자바스크립트 - 관리하기 쉬운코드 작성하기

관리하기 쉬운코드 작성하기 최근의 웹앱은 수천 줄의 자바스크립트로 이루어져 있습니다. 다른사람의 코드를 관리하는데도 많은 시간을 보내므로 관리하기 쉬운 코드를 만들어야 합니다. 이번포스트에서는 그런..

blog.sonim1.com

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
순수 자바스크립트  HTML 태그 요소 동적 추가 및 삭제

자바스크립트 HTML 태그 요소 동적 추가 및 삭제 방법은 DOM 객체를 생성하여 DOM 트리에 동적 생성/삭제하려는 내용을 추가시키면 된다.

 

1 DOM 객체 생성

document.createElement("태그이름"); 를 호출하면 HTML 태그의 DOM 객체를 생성할 수 있다.  
이제 newDIV 객체의 프로퍼티를 이용하여 <div> 태그를 완성할수 있다

 

 var newDIV = document.createElement("div");​

 

 

 

2 innerHTML 프로퍼티를 이용

innerHTML 프로퍼티를 이용하여  <div> 태그에 HTML 텍스트를 삽입

 

newDIV.innerHTML = "새로 생성된 DIV입니다.";

 

<div> 태그에 속성을 추가하거나 CSS스타일 시트도 달 수 있다.

newDIV.setAttribute("id","myDiv");

newDIV.style.backgroundColor="yellow";

 

중간과정확인 : DOM 객체 확인

<div id="myDiv"
    style="background-color:yellow">
    새로 생성된 DIV입니다.
</div>

 

 

 

3 DOM 트리에 삽입

이제 이 newDIV 객체를 DOM 트리에 삽입해보자.
DOM 객체를 DOM 트리에 삽입할 때 대표적으로 다음 2가지 방법을 활용한다.

 

부모.appendChild(DOM객체); // DOM 객체를 부모의 마지막 자식으로 삽입

부모.insertBefore(DOM객체,기준자식); // DOM 객체를 부모의 자식 객체 중 기준자식 앞에 삽입

 

다음은 앞에서 만든 newDiv 객체를 <p "id=p"> 태그의 마지막 자식으로 추가하는 자바스크립트 코드이다.
코드에 의해 newDIV가 삽입되면 DOM 트리가 바뀌고 브라우저 화면이 바로 갱신된다.

 

var p = document.getElementById("p"); // <p "id=p"> 태그의 DOM 객체 찾기
p.appendChild(newDiv);

 

 

 

4 DOM 객체의 삭제

 

removeChild() 메소드를 이용하면 부모에게서 자식 객체를 떼어낼 수 있다.

 

var removedObj = 부모.removeChild(떼어내고자하는자식객체);

 

"id=myDiv"인 DOM 객체를 DOM 트리에서 떼어내고자 하면 다음과 같이 한다

 

var myDiv = document.getElementById("myDiv");
var parent = myDiv.parentElement; // 부모 객체 알아내기
parent.removeChild(myDiv); // 부모로부터 myDiv 객체 떼어내기

 

DOM 객체가 DOM 트리에서 제거되면 브라우저 화면이 즞각 갱신되어 DOM 객체에 의해 출력된 HTML 콘텐츠가 사라진다. 떼어낸 myDiv 객체는 DOM 트리의 임의의 위치에 다시 부착할수 있다.

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
hierarchyrequesterror 계층 구조 요청 에러

 

내 경우의 발생

IE에서 div를 div에 동적으로 추가할 때 HIERARCHY_REQUEST_ERROR 발생

 

 

Description

 

The operation would yield an incorrect node tree. (작업이 잘못된 노드 트리를 생성합니다.)

 

 

Legacy code name and value

HIERARCHY_REQUEST_ERR (3)

 

 

https://www.w3.org/TR/WebIDL-1/#hierarchyrequesterror
728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,

v