1

I have been scratching my head over this problem for a while now. I have made a textarea and created a model with ng-model. This works all fine. I also have a button that uses plain Javascript for resetting the textarea. The binding stops working at that moment I click this button and I still can see my text in the other field, but the textarea is emtpy. I have recreated the problem here Fiddle.

window.onload = function () {
document.getElementById('btn').onclick = function () {
    document.getElementById('textarea').value = ""; 
};
}; 

Am I missing something here or is this not how binding works in Angular. When I start retyping it starts 'listening' again and displays the correct text.

Does somebody have a clue or encountered this problem before?

Thanks in advance.

Michelangelo
  • 5,888
  • 5
  • 31
  • 50
  • ngmodel has nothing to do with setting `document.getElementById('textarea').value = ""` Just bind ng-click on that button and reset ng-model bound property – PSL Feb 05 '15 at 20:29
  • 2
    If you are updating outside of angular, you have to do a $scope.$apply() – Scottie Feb 05 '15 at 20:36
  • @PSL There is a ng-click bound to the button that calls a function to reset the textarea. – Michelangelo Feb 05 '15 at 20:44
  • There is no `$apply` needed in this case. Triggering the `input` event on the textarea is enough, since `ng-model` listens for that and will start the digest loop internally: http://jsfiddle.net/g5s6kv28/ – tasseKATT Feb 05 '15 at 20:45
  • why would you do apply here. If you have ng-click then clear the model from there. – PSL Feb 05 '15 at 20:45
  • @PSL: He doesn't have an ng-click. Thus, he needs to do $apply. Granted, this is very un-angular to do it this way, but it can be done. I agree that implementing ng-click is the better solution, but if he can't for some reason, he'd need $apply. – Scottie Feb 05 '15 at 20:48
  • @Scottie: Check my previous comment, there is no need to call `$apply`. Not that I recommend going this route. – tasseKATT Feb 05 '15 at 20:49
  • @Scottie how will scope.$apply has anything to do with `document.getElementById('textarea').value = "";` when you are in angular you work with the model (view model) not with DOM directly. I dont know how your scope.$apply suggestion works in OPs example. – PSL Feb 05 '15 at 20:50
  • You already have good answers here, but I'd strongly recommend you read the first few answers on this question: http://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background. What you are attempting to do is less than ideal. – Aaron Greenwald Feb 05 '15 at 20:50
  • @PSL: In my answer, I link to a jsFiddle that does this. I wasn't able to get it to work without doing a $apply. You are the master here, and I'm hoping to learn something new. How would you re-write this to not use the $apply? – Scottie Feb 05 '15 at 20:52
  • @Scottie: Just check my first comment and the linked example :) – tasseKATT Feb 05 '15 at 20:53
  • @Scottie see AWolf answer. – PSL Feb 05 '15 at 20:53
  • @PSL: Sorry, I'm not trying to be obtuse here, but trying to learn something new. As I understand the OP, he's NOT using the model to update the textbox. He's doing this in a javascript function outside of angular. Which, if I'm not mistaken, requires a $apply? – Scottie Feb 05 '15 at 20:57
  • @Scottie: I feel ignored :) No $apply: jsfiddle.net/g5s6kv28 – tasseKATT Feb 05 '15 at 20:58
  • @tasseKat, I looked at your example, and it appeared that you did a very complex $apply. :) – Scottie Feb 05 '15 at 20:59
  • @Scottie `I have made a textarea and created a model with ng-model.` probably my understanding is wrong, i cannot access fiddle so cant really see.. :) – PSL Feb 05 '15 at 20:59
  • @PSL: I also have a button with plain Javascript – Scottie Feb 05 '15 at 20:59
  • @Scottie OP says `There is a ng-click bound to the button that calls a function to reset the textarea` in the first comment. i think we are all trying to solve an X/Y problem due to a design issue possibly.. :) I am confused.. over and out!! :) – PSL Feb 05 '15 at 21:00
  • Yes, `ng-click` and resetting the model in the controller is obviously the way to go :) – tasseKATT Feb 05 '15 at 21:01
  • @aarong You are right. This is my first angular project and I just wanted to add some stuff and than I realized I was falling back to jquery methods :). Thansk for your advice though. – Michelangelo Feb 05 '15 at 21:06
  • @tasseKatt Wow that (http://jsfiddle.net/g5s6kv28/) is an elegant solution to an ugly problem haha :)... Thanks. In my original file I am using an ng-click that sends data to a database and after that I try to reset. I am aware that I made a mistake in how I use a factory. – Michelangelo Feb 05 '15 at 22:15

3 Answers3

3

Here's a fiddle that will do what you are asking, but it's very un-angular.

http://jsfiddle.net/tk0a5nf1/3/

window.onload = function () {
    document.getElementById('btn').onclick = function () {
        var scope = angular.element(document.getElementById('textarea')).scope();
        scope.txt = "";
        scope.$apply();
    };
};

Here is a more angular way of doing this:

http://jsfiddle.net/h4za5ta5/

<div ng-app>
    <textarea id="textarea" ng-model="txt"></textarea>
    <div>{{txt}}</div>
    <button id='btn' ng-click='txt=""'>Reset textarea</button>
</div>
PSL
  • 123,204
  • 21
  • 253
  • 243
Scottie
  • 11,050
  • 19
  • 68
  • 109
  • This worked, but I get an error in the console saying $apply already in progress. – Michelangelo Feb 05 '15 at 20:53
  • Just to be clear, the line `document.getElementById('textarea').value = ""; ` in the first example is not needed. – tasseKATT Feb 05 '15 at 20:54
  • You are doing redundant `document.getElementById('textarea').value = ""; ` and it is a bad approach too. Digest issue is because OP already has an ng-click associated, so that entire onclick call is redundant as well. – PSL Feb 05 '15 at 20:54
  • I think this may have been confusing. These 2 code snippets were not meant to be used together. SO just forces me to put some code in. The first was how to approach the problem using javascript. The second was meant to be used without any of the javascript, using pure angular. – Scottie Feb 06 '15 at 02:22
2

Not sure why you don't use angular to reset your text area.

You can do a reset with ng-click="txt=''" with-out a function in your controller but it's better to do it like this ng-click="reset()".

For a demo see below and here at jsFiddle.

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

app.controller('MainCtrl', ['$scope', function ($scope) {
    $scope.txt='';
    
    $scope.reset = function() {
        $scope.txt = '';
    };
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.10/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="MainCtrl">
<textarea id="textarea" ng-model="txt">
    
</textarea>

    <div>{{txt}}</div>

<!--<button id='btn' ng-click="txt=''">Reset textarea</button>-->
    <button id='btn' ng-click="reset()">Reset textarea</button>
</div>
  </div>
AWolf
  • 8,770
  • 5
  • 33
  • 39
  • Before I reset I do a whole lot of stuff and I do that within a factory. So I was wondering if I could reach my $scope to reset. I am not making my functions directly in the controller. – Michelangelo Feb 05 '15 at 20:55
  • I am injecting my factory as a dependency in my controller, so my controller has access to all the functions in the factory. Why is that so bad? – Michelangelo Feb 05 '15 at 20:59
  • @Mikey Even the reset function for the view? controllers are built for the view. You generally do not put a view bound logic in a service, controllers are for that. I suspected because of your comment `I was wondering if I could reach my $scope to reset. I am not making my functions directly in the controller.` – PSL Feb 05 '15 at 21:05
  • 2
    @Mikey, Services and factories should be view agnostic, meaning they should never assume that a particular field exists on the page. Use controllers and directives for those functions. – Scottie Feb 05 '15 at 21:09
  • @Scottie Ok sorry for the confusion and bad explanation of my problem. It is just my first project with Angular. I collect data from input fields and send that to a database and after that I want to update my view (emptying textarea). I know that I am crawling back to old habits, that is why I came here to explain my problem. Thanks for the help. – Michelangelo Feb 05 '15 at 21:18
  • 1
    @PSL Thanks for the clear explanation. I learn a lot here :). – Michelangelo Feb 05 '15 at 21:26
  • @AWolf Thanks this worked out really well actually. Both your suggestions do. I was just stuck in a mindset of forcing it into one function in my factory when I easily could have done something like this. – Michelangelo Feb 05 '15 at 22:22
0

Angular doesn't like string variables for ng-model and doesn't seem to update them in my experience. I change my variable to an object with a string property and then initialize the object in the controller.

<textarea id="textarea" ng-model="txt"> would become <textarea id="textarea" ng-model="xyz.text">

In the controller I initialize xyz.

app.controller('MainCtrl', ['$scope', function ($scope) {
    $scope.xyz = { text: '' };
    
    initialize();

    function initialize() {
        $scope.xyz = { text: '' };
    };
}]);