momentJS를 angularJS 필터에서 사용하기

Problem

스크린샷 2016-01-25 오후 6.55.20

angularJS로 ERP를 만드는 중이다.
ng-repeat로 반복되는 칼럼에 타임스탬프가 안 예쁘게 찍혀서 moment.js로 가독성을 높이려 한다.

javascript에서 가로채서 솰라솰라 하는거 말고 angular로 예쁘게 하는 방법은 없을까?

 

Solution

angularjs filter를 사용한다.

sandiApp.filter('moment', function() {
    return function(dateString, format) {
        return dateString? moment(dateString).format(format): null;
    };
});

이 jsfiddle을 참고하고, 값을 입력 안하면 null이 반환되게 살짝 추가해두었다.

<td>{{ invoice.ordered_time | moment:'YYYY년 MMMM Do dddd a h:mm' }}</td>

원하는 출력 형태를 써주면 filter에서 moment(원래적히던값).format(적어준포맷)으로 모멘트를 통과해서 뿌려준다.

Outcome

스크린샷 2016-01-25 오후 7.03.20

예뻐짐.

Javascript switch문에서 정규표현식 사용하기(feat. google tag manager)

스크린샷 2016-01-11 오후 5.23.49

Problem

Google Tag Manager에서 event를 만드는데 카테고리를 현재 있는 페이지 이름으로 넣고 싶다.
하지만 그냥 page path를 가져오면 가독성이 좋지 않아 한글화를 하고 싶다.
커스텀 자바스크립트 변수로 switch로 분기태워서 나누면 될 것 같은데,
https://store.pinkfong.com/user/order/2521/에서 2521처럼 동적으로 만들어진 path가 있어 보통 switch문으로 되지 않아 정규표현식을 쓰도록 한다.

Solution

switch에 true를 넣어 무조건 안으로 넣어주고, /정규식/.test(원하는변수)식으로 분기를 태워준다.
GTM의 Custom Javascript타입으로 pathName이란 이름의 Variables를 만들고, 사용할 땐 {{ pathName }}으로 사용해주면 된다.

function() {
    var path = location.pathname;
    var name;
    switch(true) {
        case /^\/$/.test(path):
            name = "메인페이지";
            break;
        case /^\/\d+\/$/.test(path):
            name = "제품상세";
            break;
        case /^\/user\/order\/\d+\/done\/$/.test(path):
            name = "구매완료";
            break;
        case /^\/user\/order\/$/.test(path):
            name = "주문";
            break;
        case /^\/user\/order\/\d+\/$/.test(path):
            name = "주문상세";
            break;
        case /^\/cart\/$/.test(path):
            name = "장바구니";
            break;
        case /^\/order\/$/.test(path):
            name = "주문진행중";
            break;
        default:
            name = path;
    }
    return name;
}

refer

http://stackoverflow.com/questions/2896626/switch-statement-for-string-matching-in-javascript

Javascript, jQuery로 element의 index 구하기

개요

Google Analytics에서 dataLayer를 사용하는데, 제품 노출을 전달할 때 그 제품의 index를 넘겨야 한다.
하지만 tagmanager를 사용하기 위한 dataLayer는 body여는태그 바로 뒤에 삽입해서 jQuery보다 먼저 호출되고만다.

<ul class="product">
  <li class="product">
    <div class="product">
      <div class="product-image">
        <a href="/13"></a>
      </div>
      <div class="product-content">
      </div>
    </div>
  </li>
  <li class="product">...</li>
  <li class="product">...</li>
</ul>

여기서 상품번호 별 li의 index를 어떻게 가져올까?

jQuery

jQuery로는 간단하다.

var position = $('.product-image a[href='/' + {{ product.id }} + '/']&').closest('li.product').index() + 1;

하지만 jQuery를 못 쓰는게 함정

javascript

스택오버플로우에서 루프를 돌지 않고 요소의 index를 받는 함수를 올려놓은 답변을 찾았다.

function getChildNumber(node) {
  return Array.prototype.indexOf.call(node.parentNode.childNodes, node);
}

하지만 내 코드에선 1, 3, 5, 7로 찍혀 나와서 2로 나누고 반올림 해서 수정했다.

function getChildNumber(node) {
  return Math.ceil(Array.prototype.indexOf.call(node.parentNode.childNodes, node)/2);
}

그래서 완성 코드는 이렇게 되었다.

var position = getChildNumber(document.querySelector('.product-image a[href='/' + {{ product.id }} + '/']').parentNode.parentNode.parentNode);

jQuery의 closest같은 경우는 이렇게 구현할 수도 있는데 짜피 한번 쓸거라 걍 parentNode로 올라갔다.

결과

근데 html dom보다 dataLayer가 먼저 불려서 돔 위치를 파악할 수 없어서 결국 fail. 담에 더 파봐야겠다…

(+)160111 추가 내용

jQuery를 GTM 스니펫 위로 올리고, dom ready이후에 추가되는 것들은

$(function() {
 ...
});

제이쿼리로 dom이 만들어진 후에 불리도록 넣었다.

Refer

http://stackoverflow.com/questions/4649699/is-it-possible-to-get-elements-numerical-index-in-its-parent-node-without-loopi
http://stackoverflow.com/questions/22100853/dom-pure-javascript-solution-to-jquery-closest-implementation

[jquery] 브라우저 시작 지점 바꾸기

jQuery

jquery로 하면 크로스브라우징 할 필요 없이 간단하다.

var app_offset_top = $('.article-apps').offset().top;
$(window).scrollTop(app_offset_top);

javascript

창 위치를 판단하는 크로스 브라우저 코드 (IE, 오페라 vs 파이어폭스, 사파리/크롬은 양쪽 지원)

var leftPos = (typeof window.screenLeft "number") ? window.screenLeft : window.screenX;
var topPos = (typeof window.screenTop "number") ? window.screenTop : window.screenY;

이 짓 하고 있었는데 멘토님이 지나가시다가 “jquery쓰세요”하시며 알려주셨다.

Javascript history.pushState 오류 – Failed to execute ‘pushState’ on ‘History’

스크린샷 2015-08-02 오후 8.13.53

Uncaught DOMException: Failed to execute ‘pushState’ on ‘History’: A history state object with URL ‘file://localhost/Users/jayjin/Documents/Programming/2015-02-HTML5/active’ cannot be created in a document with origin ‘null’.

투두리스트 웹앱을 만들며 탭간 이동에 history를 주려고 탭을 클릭했을 때

<br />history.pushState({"method":"active"}, null, "active");

이 코드를 실행하게 해두었더니, 글 제일 위의 저런 에러가 뜨는것이었다.

역시나 스택오버플로우 님께서 도와주셨는데,

local에서 돌릴 때 경로 인식이 꼬여서 그런것이었다.

<br />history.pushState({"method":"active"}, null, "#/active");

이와같이 #/active 로 고쳐주니 정상동작!

Refer

http://stackoverflow.com/questions/20079704/javascript-history-pushstate-not-working

javascript event.target VS event.currentTarget

target vs curruntTarget

<div class="yellow" id="yellow" style="background: #ff0; width: 300px; height: 150px">
    <div class="green" style="background: #0f0; width: 200px; height: 100px"></div>
</div>

<script type="text/javascript">
var divYellow = document.getElementById('yellow');
divYellow.onclick = function(e){
    e = e || window.event;
    var target = e.target || e.srcElement; //ie대응
    var current = e.currentTarget || this; //ie대응
    alert('target: '+target.className + ' currentTarget: ' + current.className);
}
</script>

아래노랑네모에 클릭이벤트를 걸고,

  • 위초록네모 클릭-> target:위초록 curruetTarget:아래노랑
  • 아래노랑네모 클릭-> target:아래노랑 currentTarget:아래노랑

위초록네모를 클릭하면 그걸 감싸고 있는 아래노랑네모에 event가 bubbling되어 이벤트 발생.

e.target: 이벤트가 일어난 곳
e.currentTarget: 실제로 이벤트가 걸려있는 위치

jQuery curruntTarget

$( "p" ).click(function( event ) {
  alert( event.currentTarget === this ); // true
});

jquery의 curruntTarget은 this와 동일하다.

Refer

https://api.jquery.com/event.currentTarget/
http://jsfiddle.net/misteroneill/kmn4A/3/
http://lidaf.tistory.com/38

Event delegation (Javascript, jQuery)

Event Delegation

  • child element각각에 이벤트 핸들러를 달지 않고
  • parent element에 단 뒤 이벤트가 발생한 노드를 필터링해 처리.
<JS>
document.getElementById('myTd').addEventListener( 'click', function() {
   //you code goes here...
}, false );

<HTML>
<table id="myTable">
   <tbody>
      <tr>
         <td id="myTd">1, 1</td>
         <td>1, 2</td>
      </tr> 
      <tr>
         <td>2, 1</td>
         <td>2, 2</td>
      </tr>
   </tbody>
</table>

myTd에 클릭이벤트를 달았는데, 다른 td들에도 달고 싶다면
각자 노가다로 달아줄 수 있겠지만, 이럴 땐 이벤트를 위임하는 방법을 쓴다(Event Delegation).

document.getElementById( 'myTable' ).addEventListener( 'click', function( e ) {
      if( e.target && e.target.nodeName == 'TD' ) {
         //you code goes here...
      }
   }, false );

jQuery Event Delegation

  • 이벤트 위임은 이벤트의 bubble 속성을 사용한 것입니다.
  • A 엘리먼트에 이벤트 핸들러를 등록하고 싶을 때 그 엘리먼트에 바로 붙이지 않고 그보다 상위 엘리먼트에 B에 등록합니다.
  • 이벤트가 A에서 발생했어도 B로 bubble 되어 올라가는데 이때 B에 등록된 핸들러에서 A에서 발생한 것인지 살펴보고 맞으면 이벤트 핸들러를 실행하는 방식이 이벤트 위임입니다.
  • .bind(), .live(), .delegate() 메서드 모두 jQuery 내부적으로는 .on() 메서드를 사용하게 소스코드가 바뀌었습니다.
  • 그래서 jQuery 1.7 이상 버전을 사용하신다면 여러 메서드들 중 하나를 선택하실 필요없이 그냥 .on() 메서드를 사용하시면 됩니다.
// Attach a delegated event handler
$( "#list" ).on( "click", "a", function( event ) {
    event.preventDefault();
    console.log( $( this ).text() );
});

Refer

http://regularmotion.kr/javascript-patterns-event-delegate/
http://hersheyweb.blogspot.kr/2013/04/javascript-event-delegation.html
http://codefactory.kr/2011/12/07/jquery-performance-tips-and-tricks/
http://learn.jquery.com/events/event-delegation/