Haseeb Haseeb - 1 month ago 7
AngularJS Question

Why is angular $scope not removing old value?

I have the following controller

angular.module('publicApp')
.controller('URLSummaryCtrl', function ($scope, $location, Article, $rootScope, $timeout) {
$scope._url = "";
$scope._title = "";
$scope._article = "";
$scope._authors = "";
$scope._highlights = [];
$scope._docType = "";

$scope.summarizeURL = function(){

Article.getArticleInfo($scope.url, "").then(
function(data){

$scope._url = data.url;
$scope._title = data.title;
$scope._authors = data.authors.join(', ');
$scope._highlights = data.highlights;
$scope._docType = data.documentType;

if($scope._docType == 'html'){
$scope._article = data.article[0].article;
}
else{
$scope._article = data.article;
}

var _highlights = [];
$scope._highlights.forEach(function (obj) {
_highlights.push(obj.sentence);
});

// wait for article text to render, then highlight
$timeout(function () {
$('#article').highlight(_highlights, { element: 'em', className: 'highlighted' });
}, 200);
}
);
}


and the following view

<form role="form" ng-submit="summarizeURL()">
<div class="form-group">
<input id="url" ng-model="url" class="form-control" placeholder="Enter URL" required>
</div>
<button class="btn btn-success" type="submit">Summarize</button>
</form>

<div class="col-lg-8">
<h2>{{ _title }}</h2>
<p> <b>Source: </b> <a href="{{_url}}" target="_blank">{{_url}}</a></p>
<p> <b>Author: </b> {{_authors}} </p>
<p> <b>Article: </b><p id="article">{{_article}}</p></p>
</div>


When I give a url in the text field initially and click Summarize it works as expected. But when I change the value in the text field and click the button again every thing is updated properly, with the new values, but the
$scope._article
gets the new value and doesn't remove the old value. It displays both the new and the old value that was there before.

Why is this happening?

EDIT #1: I added more code that I had. I found that when I remove the
$timeout(function(){...})
part it works as expected. So now the question is, why is
$scope._article
keeping the old value and pre-pending the new value?

EDIT #2: I found that
$timeout(...)
is not the problem. If I change

$timeout(function () {
$('#article').highlight(_highlights, { element: 'em', className: 'highlighted' });
}, 200);


to

$('#article').highlight(_highlights, { element: 'em', className: 'highlighted' });


it still behaves the same way. So now I'm assuming it's because I'm changing the $scope._article to be something else? What's happening is that I'm displaying the
$scope._article
value and then modifying what's displayed to contain highlights
<em class='highlighed'> ... </em>
on what ever I want to highlight.

EDIT #3: I tried to remove the added html before making the request to get new data but that doesn't work either. Here's the code I tried.

angular.module('publicApp')
.controller('URLSummaryCtrl', function ($scope, $location, Article, $rootScope, $timeout) {
$scope._url = "";
$scope._title = "";
$scope._article = "";
$scope._authors = "";
$scope._highlights = [];
$scope._docType = "";

$scope.summarizeURL = function(){
//Remove added html before making call to get new data
$('.highlighted').contents().unwrap();

Article.getArticleInfo($scope.url, "").then(
function(data){ ... }
);

Answer

Jquery in angular controllers = headache.

The problem is probably here for you

$timeout(function () {
        $('#article').highlight(_highlights, { element: 'em', className: }, 200);

#article.html() here, is going to give weird output, because angular has it's own sync system and the jquery library you're using has it's own way of working with the DOM. Throw in the fact that asynchronous javascript is already a pain if you're working with multiple things.

What you want instead is to set the html to the angular scope variable before you work with it in jquery so you know what the jquery is working with, i.e.:

$timeout(function () {
        $('#article').html($scope._article);
        $('#article').highlight(_highlights, { element: 'em', className: }, 200);