2013-03-07 10 views
28

से काम नहीं कर रहा है मैं एक निर्देश लिख रहा हूं जिसके लिए एक अलग दायरे की आवश्यकता है, लेकिन मैं ngModel के माध्यम से इसे मूल दायरे में बांधना चाहता हूं।

यहां समस्या यह है कि माता-पिता का दायरा मूल्य बदल नहीं रहा है।

मार्कअप

<form name="myForm" ng-app="customControl"> 
    <div ng-init="form.userContent"></div> 
    <div contenteditable name="myWidget" ng-model="form.userContent" required>Change me!</div> 
    <span ng-show="myForm.myWidget.$error.required">Required!</span> 
    <hr /> 
    <textarea ng-model="form.userContent"></textarea> 
</form> 

जे एस

angular.module('customControl', []).directive('contenteditable', function() { 
    return { 
     restrict : 'A', // only activate on element attribute 
     require : '?ngModel', // get a hold of NgModelController 
     scope: {}, 
     link : function(scope, element, attrs, ngModel) { 
      if (!ngModel) 
       return; // do nothing if no ng-model 

      // Specify how UI should be updated 
      ngModel.$render = function() { 
       element.html(ngModel.$viewValue || ''); 
      }; 

      // Listen for change events to enable binding 
      element.bind('blur keyup change', function() { 
         scope.$apply(read); 
        }); 
      read(); // initialize 

      // Write data to the model 
      function read() { 
       ngModel.$setViewValue(element.html()); 
      } 
     } 
    }; 
}); 

डेमो: Fiddle

यह ठीक काम करता है अगर मैं निर्देश

डेमो के लिए एक अलग दायरे का उपयोग नहीं करते: Fiddle

+0

चाहिए नहीं 'element.html (ngModel $ viewValue ...।) होना' element.html ($ sce.getTrustedHtml (ngModel $। viewValue) ..) मुझे पता है कि यह लगभग ng दस्तावेज़ उदाहरण के समान ही है, लेकिन मैंने अभी यह पाया है कि यह प्रभावी रूप से xss सुरक्षा को बाईपास करता है। – cirrus

+0

@arun क्या आप समझा सकते हैं कि अलग-अलग दायरे क्यों काम नहीं कर रहा है? – geckob

+0

पुन @ सीरसस टिप्पणी, मुझे लगता है कि एक्सएसएस से बचने के लिए, जब भी तत्व में कुछ भी रखा जाता है, इसे पहले $ sanitize (यानी एचटीएमएल पर भरोसा नहीं) के साथ स्वच्छ किया जाना चाहिए। Element.html की तरह कुछ ($ sanitize (ngModel। $ ViewValue)) '। – Soferio

उत्तर

41

कारण यह है कि चूंकि आप अपने contenteditable निर्देश के लिए एक अलग दायरा बना रहे हैं, इसलिए ng-model उसी तत्व पर निर्देश उस अलग-अलग दायरे को भी प्राप्त करता है। जिसका अर्थ है कि आपके पास दो अलग-अलग स्कोप हैं जो एक दूसरे से जुड़े नहीं हैं, दोनों में form.userContent संपत्ति है जो अलग-अलग बदलती है। मुझे लगता है कि आप इस कोड से यह उदाहरण देना हो सकता है:

<!doctype html> 
<html ng-app="myApp"> 
<head> 
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> 
    <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script> 
    <script> 
    angular.module('myApp', []).controller('Ctrl', function($scope) { 

    }) 
    .directive('contenteditable', function() { 
     return { 
      restrict : 'A', // only activate on element attribute 
      require : '?ngModel', // get a hold of NgModelController 
      scope: {}, 
      link : function(scope, element, attrs, ngModel) { 
       if (!ngModel) 
        return; // do nothing if no ng-model 

       setInterval(function() { 
        if (angular.element('#contenteditable').scope().form) 
         console.log(angular.element('#contenteditable').scope().form.userContent); 

        if (angular.element('#textarea').scope().form) 
         console.log(angular.element('#textarea').scope().form.userContent); 
       }, 1000); 

       // Specify how UI should be updated 
       ngModel.$render = function() { 
        element.html(ngModel.$viewValue || ''); 
       }; 

       // Listen for change events to enable binding 
       element.bind('blur keyup change', function() { 
          scope.$apply(read); 
         }); 
       read(); // initialize 

       // Write data to the model 
       function read() { 
        ngModel.$setViewValue(element.html()); 
       } 
      } 
     }; 
    }); 
    </script> 
</head> 
<body ng-controller="Ctrl"> 
    <form name="myForm"> 
     <div ng-init="form.userContent"></div> 
     <div contenteditable name="myWidget" ng-model="form.userContent" id="contenteditable" required>Change me!</div> 
     <span ng-show="myForm.myWidget.$error.required">Required!</span> 
     <hr /> 
     <textarea ng-model="form.userContent" id="textarea"></textarea> 
    </form> 
</body> 
</html> 

आप अपने कंसोल में देखेंगे, वहाँ दो अलग-अलग दायरों और form.userContent उन पर अलग से बदलने के लिए यदि आप पाठ क्षेत्र में पाठ बदलने के लिए या कर रहे हैं आप के परिवर्तित होने अपने संतुष्ट div में पाठ।

तो मुझे यकीन है कि आप सोच रहे हैं "समझाओ और मुझे समाधान दिखाएं!"। खैर, मेरे (मेरे ज्ञान के लिए) इस के लिए एक सुंदर समाधान नहीं है, लेकिन एक ऐसा काम करता है जो काम करता है। आप जो करना चाहते हैं वह मॉडल को आपके अलग-अलग दायरे में संदर्भित करता है, और सुनिश्चित करें कि आपके अलग-अलग दायरे में समान नाम है जैसा कि मूल दायरे में है। आप इस तरह के मॉडल के लिए बाध्य

... 
scope: {} 
... 

:

यहाँ आप क्या करना है, बजाय इस तरह एक खाली गुंजाइश बनाने की

... 
scope: { 
    model: '=ngModel' 
} 
.... 

अब आप अपने अलग गुंजाइश पर एक model संपत्ति है आपके माता-पिता के दायरे पर form.userContent का संदर्भ है। लेकिन ng-modelmodel संपत्ति की तलाश नहीं कर रहा है, यह form.userProperty की तलाश में है जो अभी भी हमारे अलग दायरे में मौजूद नहीं है। तो यह तय करने के लिए, हम अपने को जोड़ने समारोह के अंदर इस जोड़ें:

scope.$watch('model', function() { 
    scope.$eval(attrs.ngModel + ' = model'); 
}); 

scope.$watch(attrs.ngModel, function(val) { 
    scope.model = val; 
}); 

पहले घड़ी है कि हमारे निर्देश के बाहर से हमारे अलग form.userContent की बात आती है form.userContent पर परिवर्तन सिंक करता है, और दूसरा घड़ी सुनिश्चित करें कि हम किसी भी परिवर्तन का प्रचार करता है हमारे अलग form.userContent पर माता-पिता के दायरे तक।

मुझे एहसास है कि यह एक लंबा जवाब है, और शायद पालन करना बहुत आसान नहीं है। इसलिए मुझे कुछ भी स्पष्ट करने में खुशी होगी जो आपको लगता है कि धुंधला है।

+2

जब आप कहते हैं "[...] उसी तत्व पर एनजी-मॉडल निर्देश भी अलग-अलग गुंजाइश प्राप्त करता है। जिसका अर्थ है कि आपके पास दो अलग-अलग स्कोप हैं जो एक-दूसरे से जुड़े नहीं हैं", यदि एक ही अलग क्षेत्र है 'एनजी-मॉडल' और 'संतुष्ट' दोनों द्वारा साझा किया गया, फिर आप कैसे कहते हैं कि उनके पास दो अलग-अलग स्कोप हैं? यह एक विरोधाभास की तरह दिखता है। या क्या मैं कुछ न कुछ भूल रहा हूं? – Behrang

+0

@anders मैं स्पष्ट नहीं हूं कि अलग-अलग दायरे कोड को कैसे तोड़ते हैं। क्या आप स्पष्ट कर सकते हैं? – geckob

+0

@ एंडर्स Ekdahl यदि किसी तत्व पर एकाधिक निर्देश एक अलग दायरे प्रदान करते हैं, तो केवल एक नया दायरा लागू होता है। (संदर्भ एनजी-बुक, पृष्ठ 111, स्कोप विकल्प शीर्षक) –

4

पहला जवाब समस्या को अच्छी तरह से बताता है, मेरा मानना ​​है कि मेरे पास एक आसान समाधान है जो अतिरिक्त घड़ियों से बचाता है।

उत्तर 1 सारांशित करने के लिए।ngModel अलग-अलग दायरे के अंदर काम नहीं कर सकता है क्योंकि जिन तत्वों का आप इरादा रखते हैं वे इसके दायरे में नहीं हैं। वे माता-पिता के दायरे में हैं।

समाधान 1, माता पिता की संपत्ति को बाँध

<div contenteditable name="myWidget" ng-model="form.userContent" required>Change me!</div> 

हो जाता है

<div contenteditable name="myWidget" ng-model="$parent.form.userContent" required>Change me!</div> 

समाधान 2, अलग गुंजाइश

require : '?ngModel',require : '?^ngModel', हो जाता है बाहर ले जाने के ngModel^अपने निर्देश बताता है देखने के लिए ngModel

0 के लिए मूल तत्वों में

हो जाता है

<div ng-model="form.userContent"> 
    <div contenteditable name="myWidget" required>Change me!</div> 
</div> 
+0

मुझे यह उत्तर बिंदु और सबसे उपयोगी पाया गया। आप दोहरी-$ घड़ी दृष्टिकोण के साथ जवाब पूरा करना चाहते हैं क्योंकि यह एक वैध (और व्यापक रूप से लागू) समाधान है। –

-1

Ido't पता है कि यू वास्तव में चाहते हैं, यू यह कोशिश कर सकते हैं।

एचटीएमएल:

<form name="myForm" ng-app="customControl"> 
    <div ng-init="form.userContent"></div> 
    <div contenteditable name="myWidget" ng-model="form" required>Change me!</div> 
    <span ng-show="myForm.myWidget.$error.required">Required!</span> 
    <hr /> 
    <textarea ng-model="form.content"></textarea> 
</form> 

js

angular.module('customControl', []).directive('contenteditable', function() { 
    return { 
     restrict : 'A', // only activate on element attribute 
     require : '?ngModel', // get a hold of NgModelController 
     link : function(scope, element, attrs, ngModel) { 
      if (!ngModel) 
       return; // do nothing if no ng-model 
      // Specify how UI should be updated 
      ngModel.$render = function() { 
       element.html(ngModel.$viewValue || ''); 
      }; 

      // Listen for change events to enable binding 
      element.bind('blur keyup change', function() { 
         scope.$apply(read); 
        }); 
      read(); // initialize 

      // Write data to the model 
      function read() { 
       ngModel.$setViewValue({'content': element.html()}); 
      } 
     } 
    }; 
}); 
संबंधित मुद्दे