AngularJS의 * 자신의 범위 *로 사용자 지정 지시문 내에서 부모 범위에 액세스하는 방법은 무엇입니까?


327

지시문 내에서 "부모"범위에 액세스하는 방법을 찾고 있습니다. 범위, transclude, require, 위의 변수 (또는 범위 자체) 전달 등의 모든 조합. 나는 완전히 뒤로 기꺼이 구부리고 싶지만 완전히 해킹하거나 유지할 수없는 것을 피하고 싶습니다. 예를 들어, $scopepreLink 매개 변수에서 가져 와서 $sibling개념 "부모"를 찾기 위해 범위를 반복 함으로써 지금 당장 할 수 있다는 것을 알고 있습니다.

내가 정말로 원하는 것은 $watch부모 범위에서 식 을 사용할 수 있도록 하는 것입니다. 그렇게 할 수 있다면 여기서 시도하고있는 것을 성취 할 수 있습니다 : AngularJS-변수로 부분을 렌더링하는 방법?

중요한 사항 은 지시문을 동일한 상위 범위 내에서 재사용 할 수 있어야한다는 것입니다. 따라서 기본 동작 (scope : false)이 작동하지 않습니다. 지시문의 인스턴스마다 개별 범위가 필요 $watch하며 부모 범위에있는 변수가 필요합니다 .

코드 샘플의 가치는 1000 단어이므로

app.directive('watchingMyParentScope', function() {
    return {
        require: /* ? */,
        scope: /* ? */,
        transclude: /* ? */,
        controller: /* ? */,
        compile: function(el,attr,trans) {
            // Can I get the $parent from the transclusion function somehow?
            return {
                pre: function($s, $e, $a, parentControl) {
                    // Can I get the $parent from the parent controller?
                    // By setting this.$scope = $scope from within that controller?

                    // Can I get the $parent from the current $scope?

                    // Can I pass the $parent scope in as an attribute and define
                    // it as part of this directive's scope definition?

                    // What don't I understand about how directives work and
                    // how their scope is related to their parent?
                },
                post: function($s, $e, $a, parentControl) {
                    // Has my situation improved by the time the postLink is called?
                }
            }
        }
    };
});

답변:


644

AngularJS에서 스코프 프로토 타입 / 프로토 타입 상속의 뉘앙스는 무엇입니까?를 참조하십시오 .

요약 : 지시문이 부모 ( $parent) 범위에 액세스하는 방법 은 지시문이 생성하는 범위 유형에 따라 다릅니다.

  1. default ( scope: false)-지시문이 새 범위를 작성하지 않으므로 여기에는 상속이 없습니다. 지시문의 범위는 부모 / 컨테이너와 동일한 범위입니다. 링크 함수에서 첫 번째 매개 변수 (일반적으로 scope)를 사용하십시오 .

  2. scope: true-지시문은 부모 범위에서 프로토 타입으로 상속되는 새로운 자식 범위를 만듭니다. 부모 범위에 정의 된 속성 scope은 프로토 타입 상속으로 인해 지시문에서 사용할 수 있습니다 . 프리미티브 스코프 속성에 쓰는 것을주의하십시오. 지시문 범위에 새 속성이 만들어집니다 (같은 이름의 부모 범위 속성을 숨기거나 가리기).

  3. scope: { ... }-지시문은 새로운 분리 / 분리 범위를 만듭니다. 부모 범위를 프로토 타입으로 상속하지 않습니다. 을 사용하여 부모 범위에 계속 액세스 할 수 $parent있지만 일반적으로 권장되지는 않습니다. 대신 지정해야하는 부모 범위 속성을 (및 / 또는 기능) 추가 지시어 사용되는 동일한 요소에 속성의 사용을 통해 지침의 요구 =, @그리고 &표기법을.

  4. transclude: true-지시문은 부모 범위에서 프로토 타입으로 상속되는 새로운 "번역 된"하위 범위를 작성합니다. 지시문이 분리 범위를 작성하는 경우 변환 된 범위와 분리 범위는 형제입니다. $parent각 범위 의 속성은 동일한 부모 범위를 참조합니다.
    Angular v1.3 업데이트 : 지시어가 격리 범위를 생성하는 경우 이제 포함 된 범위는 격리 범위의 자식입니다. 포함 및 격리 범위는 더 이상 형제가 아닙니다. $parent포함 된 범위 의 속성은 이제 격리 범위를 참조합니다.

위의 링크에는 4 가지 유형의 예와 그림이 있습니다.

지시어의 컴파일 함수에서 범위에 액세스 할 수 없습니다 ( https://github.com/angular/angular.js/wiki/Understanding-Directives ). 링크 함수에서 지시문의 범위에 액세스 할 수 있습니다.

보고있다:

위의 1과 2의 경우 : 일반적으로 속성을 통해 지시문에 필요한 부모 속성을 지정한 다음 $ watch합니다.

<div my-dir attr1="prop1"></div>

scope.$watch(attrs.attr1, function() { ... });

객체 속성을보고 있다면 $ parse를 사용해야합니다.

<div my-dir attr2="obj.prop2"></div>

var model = $parse(attrs.attr2);
scope.$watch(model, function() { ... });

위의 3. (범위 분리)의 경우 @또는 =표기법을 사용하여 지시문 속성에 지정한 이름을 확인하십시오 .

<div my-dir attr3="{{prop3}}" attr4="obj.prop4"></div>

scope: {
  localName3: '@attr3',
  attr4:      '='  // here, using the same name as the attribute
},
link: function(scope, element, attrs) {
   scope.$watch('localName3', function() { ... });
   scope.$watch('attr4',      function() { ... });

1
감사합니다, 마크 변수로 부분을 렌더링하는 방법에 게시 한 솔루션이 실제로 아름답게 작동 한다는 것이 밝혀졌습니다 . 저를 연결하기 위해 정말로 필요한 것은 "HTML을 작성하고 요소가 생각하는 ng-controller 안에 중첩되어 있지 않다는 것을 인식하는 뉘앙스"였습니다. 와우 ... 신인 실수. 그러나 이것은 범위를 설명하는 다른 (훨씬 긴) 답변에 유용한 추가 사항입니다.
colllin

@collin, 좋습니다. 다른 (현재 삭제 된) 의견에 응답하는 방법을 잘 모르기 때문에 문제를 해결하게되어 기쁩니다.
Mark Rajcok

내가 수행 할 수있는 것들scope.$watch('localName3', function() { ...[?? WHAT TO DO HERE for example?] });
Junaid Qadir

1
@Andy, $parse와 함께 사용하지 마십시오 =: fiddle . $parse비 격리 범위에만 필요합니다.
Mark Rajcok

1
이것은 매우 철저한 답변입니다. 또한 내가 AngularJS로 작업하는 것을 싫어하는 이유도 설명합니다.
John Trichereau

51

컨트롤러 메소드에 액세스하는 것은 지시문 컨트롤러 / 링크 / 범위에서 상위 범위의 메소드에 액세스하는 것을 의미합니다.

지시어가 부모 범위를 공유 / 상속하는 경우 부모 범위 메서드를 호출하는 것이 매우 간단합니다.

Isolated 지시문 범위에서 부모 범위 메서드에 액세스하려는 경우 더 많은 작업이 필요합니다.

분리 된 지시문 범위에서 부모 범위 메서드를 호출하거나 부모 범위 변수 ( 특히 옵션 # 6 )를 볼 수있는 옵션은 거의 없습니다 (아래에 나열된 것보다 많을 수 있음 ).

참고 내가 사용하는 것이 link function이러한 예에 있지만, 당신이 사용할 수있는 directive controller요구 사항에뿐만 아니라 기반으로합니다.

옵션 1. 객체 리터럴과 지시문 HTML 템플릿을 통해

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChanged({selectedItems:selectedItems})" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]

});

작업 plnkr : http://plnkr.co/edit/rgKUsYGDo9O3tewL6xgr?p=preview

옵션 # 2. 객체 리터럴과 지시문 링크 / 범위를 통해

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html",
    link: function (scope, element, attrs){
      scope.selectedItemsChangedDir = function(){
        scope.selectedItemsChanged({selectedItems:scope.selectedItems});  
      }
    }
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

작업 plnkr : http://plnkr.co/edit/BRvYm2SpSpBK9uxNIcTa?p=preview

옵션 # 3. 함수 참조 및 지시문 HTML 템플리트를 통해

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-change="selectedItemsChanged()(selectedItems)" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems:'=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

작업 plnkr : http://plnkr.co/edit/Jo6FcYfVXCCg3vH42BIz?p=preview

옵션 # 4. 함수 참조 및 지시문 링크 / 범위를 통해

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html",
    link: function (scope, element, attrs){
      scope.selectedItemsChangedDir = function(){
        scope.selectedItemsChanged()(scope.selectedItems);  
      }
    }
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]

});

작업 plnkr : http://plnkr.co/edit/BSqx2J1yCY86IJwAnQF1?p=preview

옵션 # 5 : ng-model 및 양방향 바인딩을 통해 상위 범위 변수를 업데이트 할 수 있습니다. . 따라서 경우에 따라 상위 범위 함수를 호출하지 않아도됩니다.

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter ng-model="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=ngModel'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

작업 plnkr : http://plnkr.co/edit/hNui3xgzdTnfcdzljihY?p=preview

옵션 # 6 : 통과 $watch$watchCollectionitems 위의 모든 예에서 양방향 바인딩입니다 . 항목이 상위 범위에서 수정되면 지시문의 항목도 변경 사항을 반영합니다.

부모 범위에서 다른 속성이나 객체를보고 싶다면 아래에서 $watch$watchCollection같이 사용하십시오.

html

<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <p>Hello {{user}}!</p>
  <p>directive is watching name and current item</p>
  <table>
    <tr>
      <td>Id:</td>
      <td>
        <input type="text" ng-model="id" />
      </td>
    </tr>
    <tr>
      <td>Name:</td>
      <td>
        <input type="text" ng-model="name" />
      </td>
    </tr>
    <tr>
      <td>Model:</td>
      <td>
        <input type="text" ng-model="model" />
      </td>
    </tr>
  </table>

  <button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>

  <p>Directive Contents</p>
  <sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>

  <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
</body>

</html>

스크립트 app.js

var app = angular.module ( 'plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      name: '@',
      currentItem: '=',
      items: '=',
      selectedItems: '=ngModel'
    },
    template: '<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"' +
      'ng-options="item.id as item.name group by item.model for item in items | orderBy:\'name\'">' +
      '<option>--</option> </select>',
    link: function(scope, element, attrs) {
      scope.$watchCollection('currentItem', function() {
        console.log(JSON.stringify(scope.currentItem));
      });
      scope.$watch('name', function() {
        console.log(JSON.stringify(scope.name));
      });
    }
  }
})

 app.controller('MainCtrl', function($scope) {
  $scope.user = 'World';

  $scope.addItem = function() {
    $scope.items.push({
      id: $scope.id,
      name: $scope.name,
      model: $scope.model
    });
    $scope.currentItem = {};
    $scope.currentItem.id = $scope.id;
    $scope.currentItem.name = $scope.name;
    $scope.currentItem.model = $scope.model;
  }

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
  }]
});

지시문에 대한 자세한 설명은 항상 AngularJs 설명서를 참조하십시오.


10
그는 그의 담당자를 위해 열심히 일하고 ... 그의 담당자를 위해 열심히 일하고 ...
날씬한

7
을 downvoted - 대답 내의 가치있는 정보로 인해 길이에 액세스 할 수 없습니다
구제

2
나는 가능한 모든 대안으로 명확한 분리로 질문에 대답했습니다. 내 의견으로는, 짧은 답변이 당신 앞에서 큰 그림을 볼 때까지 항상 도움이되는 것은 아닙니다.
Yogesh Manware

@ YogeshManware : 긴 마크 업을 사용하지 않고 스타일 시트와 같은 관련이없는 항목을 생략하고, "group by"와 같은 것을 사용하지 않도록 예제를 단순화하는 등 많은 시간을 단축 할 수 있습니다. 각 예.
11

이것은 투표권을 떨어 뜨릴 이유가 아닙니다. 사람들은이 특권을 남용합니다
Winnemucca

11
 scope: false
 transclude: false

그리고 당신은 같은 범위를 가질 것입니다 (부모 요소와 함께)

$scope.$watch(...

이 두 가지 옵션 범위 및 변환에 따라 상위 범위에 액세스하는 방법에는 여러 가지가 있습니다.


예, 짧고 달콤하며 정확합니다. 그래도 부모 요소와 동일한 범위를 공유하는 것 같습니다 ... 이는 동일한 범위에서 재사용 할 수 없습니다. jsfiddle.net/collindo/xqytH
colllin

2
재사용 할 수있는 컴포넌트를 작성할 때 분리 된 범위가 필요한 경우가 많으므로 솔루션은 그렇게 간단하지 않습니다
Yvon Huynh

8

한 번 사용한 트릭은 다음과 같습니다. "더미"지시문을 작성하여 상위 범위를 보유하고 원하는 지시문 외부에 배치하십시오. 다음과 같은 것 :

module.directive('myDirectiveContainer', function () {
    return {
        controller: function ($scope) {
            this.scope = $scope;
        }
    };
});

module.directive('myDirective', function () {
    return {
        require: '^myDirectiveContainer',
        link: function (scope, element, attrs, containerController) {
            // use containerController.scope here...
        }
    };
});

그리고

<div my-directive-container="">
    <div my-directive="">
    </div>
</div>

아마도 가장 우아한 해결책은 아니지만 일을 마쳤습니다.


4

ES6 클래스 및 ControllerAs구문을 사용하는 경우 약간 다른 작업을 수행해야합니다.

아래 스 니펫을 참조 하여 상위 HTML에 사용 된 상위 컨트롤러 vmControllerAs값입니다.

myApp.directive('name', function() {
  return {
    // no scope definition
    link : function(scope, element, attrs, ngModel) {

        scope.vm.func(...)

0

모든 것을 시도한 후에 마침내 해결책을 찾았습니다.

템플릿에 다음을 배치하십시오.

{{currentDirective.attr = parentDirective.attr; ''}}

현재 범위에 액세스하려는 상위 범위 속성 / 변수 만 작성합니다.

또한 ; ''명령문 끝에서 템플릿에 출력이 없는지 확인해야합니다. (Angular는 모든 명령문을 평가하지만 마지막 명령문 만 출력합니다).

약간 해 키지 만 몇 시간의 시행 착오 후에 일을합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.