1

I have a Html page with a text box and am using a bit of AngularJS to display the count of characters remaining -

<div ng-app="" class="container-fluid">
        <form class="form" role="form">
            <div class="form-group">
                @Html.TextArea("Description", htmlAttributes: new { @class = "form-control", placeholder = "Description, ng_model = "descMessage" })
                <div>
                    <label>{{ 500 - descMessage.length }}</label>
                </div>
            </div>
        </form>
</div>

This works fine when I am simply displaying it as a partial view. I get correct count of chars remaining.

@Html.Partial("~/Views/Desc/Index.cshtml")

But does not work when I display it via JQuery. Instead of chars remaining, it always displays the actual text as - {{ 500 - descMessage.length }}.

var options = {
        url: "/Desc/Index",
        type: "get",
        dataType: "html"
    };

    $.ajax(options).done(function (data) {
        var $target = $("#displayform");
        $target.html(data);

    });

The AngularJS expression was supposed to be evaluated here. Why does this not happen? I have used JQuery a lot in my experience, but first time using AngularJS along with it. How can I go about fixing this?

Sam
  • 4,302
  • 12
  • 40
  • 74

1 Answers1

1

This is tricky because you're attempting to modify data outside of Angular's "world". It seems easy enough to do, but because you're creating elements that are bound to Angular, it's taking some liberties with the content that can go in there, or rather how it's "rendered" by Angular.

tl;dr; - you need to use the $sce provider with Angular inside a controller in order to "trust" new content as HTML; use $sce.trustAsHtml(content). Best approach would be to actually create a controller here and attach it to your form with ng-controller.

The trick will be to use ng-change on the textarea to hook to the text changing instead of using jQuery. From a recently converted hardcore jQuery guy to one who now prefers to live inside Angular's "world", I can tell you that using events, controllers, and http.get has a lot of similarities and is easy to work with.

Here's some pseudo-code to quickly get you going:

HTML Pseudo Markup:

<form ng-controller="myController as ctrl">
  ...
  <textarea ... ng-model="textinput" ng-change="ctrl.updateLength()"></textarea>
  <span ng-bind-html="ctrl.textRemainingDisplay">
</form>

Notice ng-model in there - we'll use that in the change event handler. The other critical piece is the display, which we us ng-bind-html; the $sce provider below will give us a render in the format needed to bind without any further ado.

Javascript Pseudo markup:

angular.module("myModule",[]).controller("myController", function($scope, $http, $sce)
{
  this.updateLength = function()
  {
      this.textRemainingDisplay = $sce.trustAsHtml(500-this.textinput.length);
  }
});

You could [probably should] use a directive to do the same thing, I just think as someone who's also learning Angular that controllers are a little easier to digest. Difference would be some syntax on the controller (using directive instead and returning an object) and then the markup on the span would go something like <span mydirective></span> and the created directive would have the same scope as what we did above.

Again this is just pseudo-code, I haven't tested anything but it should work to get you a simple counter in pure Angular that doesn't require jQuery and Angular together.

HTH!

Scott Byers
  • 3,007
  • 2
  • 17
  • 14
  • I really thought there is a simpler way of doing this, as for me it seems Angular is just losing the binding and I only need to re-adjust it (after loading the html possibly). I could easily build a jQuery counter, but don't want to when Angular does it so wonderfully for me. Anyways, will try implementing your solution and see if it works. – Sam Feb 08 '15 at 15:18
  • The trouble is that Angular doesn't know that the value has changed because it's happened outside the application scope. I just recently dealt with a handful of similar issues. You may be able to invoke the update in your jQuery code by getting a handle to the Angular module - I saw a couple of solutions that did it but they were all more complicated than using a controller or directive and pure Angular. The little bit saved in using the familiar jQuery code is quickly lost when combining the two to manipulate DOM "contents" on elements that have been bound to Angular. – Scott Byers Feb 08 '15 at 16:20