$scope variable not updating in view - javascript

I have the following snippet of code,
<div ng-controller="GraphCtrl" ng-if="errorTracerouteResultsLength!=0">
<h5>Erroneous Traceroute Paths
<small>Sub-heading</small>
</h5>
<a href="#" ng-repeat="(key, val) in errorTracerouteResults" ng-click="loadTraceroutePath(val.metadata);">
S: {{val.source.ip}}
D: {{val.destination.ip}}
</a>
</div>
It works fine, loadTraceroutePath belongs to another controller,(lets call it X) but somehow ng-click works and console.log gets printed out with the correct metadata value.
However, in controller X, I have,
$scope.loadIndividualTraceroutePath = function (metadataKey) {
$scope.noOfResults = 1;
}
In the html, I have {{noOfResults}} all over the place. Some of it are able to display 1 while some can't. I have already attached the ng-controller directives and point to controller X, but {{noOfResults}} does not display.
How can I make {{noOfResults}} display in any section of the HTML?
Edit: I have added the HTML.
<div class="row">
<div class="col-lg-9">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bar-chart-o fa-fw"></i> Visualisation
<div class="pull-right">
Layout
</div>
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div class="container" ng-controller="X">
<!--This does not work-->
{{noOfResults}}
</div>
<div>
<div ng-controller="IndividualTraceroutePathGraphCtrl" id="individual_traceroute_path_graph"></div>
</div>
</div>
<!-- /.panel-body -->
</div>
<!-- /.panel -->
</div>
The ng click in the first part of this question is way below.

You have a extra ; at the end, also you are not using the object what you are passing as a parameter to the function, hence Change
From:
<a href="#" ng-repeat="(key, val) in errorTracerouteResults" ng-click="loadTraceroutePath(val.metadata);">
To:
<a href="#" ng-repeat="(key, val) in errorTracerouteResults" ng-click="loadTraceroutePath(val)">
Then,
$scope.loadIndividualTraceroutePath = function (metadataKey) {
$scope.noOfResults = 1;
}
EDIT
You don't need to mention so many controllers in the view, have one controller where the function is defined and remove the rest, here, Update like this,
<div class="container" >
<!--This does not work-->
{{noOfResults}}
</div>
<div>
<div id="individual_traceroute_path_graph"></div>
</div>
</div>

Related

Avoid JavaScript Replication in partial views

This code is used to remove a cart-item from a partial view.
$(document).on('click', '.RemoveLink', (function (e) {
e.preventDefault();
var recordToDelete = $(this).attr("data-id");
var itemID = $(this).attr("data-itemid");
if (recordToDelete != '') {
$.post("/ShoppingCart/RemoveFromCart", { "id": recordToDelete, "itemID": itemID },
function () {
$('.container-cart').load('#Url.Action("cartDropDown","ShoppingCart")', function () {
$('.cart-dropdown').css('display', 'inline-block');
}
);
});
}
}));
This works well for the first iteration but from the second iteration on-wards, every click of a remove of an item is resulting in deletion of 2 items of a kind. Suppose we had 4 items of pencils and 8 items of pens. Clicking delete pencil button once will result in deletion of 2 pencils and vice versa.
This is probably because of the logic used. Following is the html that is rendered when $('.container-cart').load('#Url.Action("cartDropDown","ShoppingCart")' executes:
#model OnlineStore.ViewModels.ShoppingCartViewModel
<div class="container-cart">
#if (Model.ItemCount == 0)
{
<div>
<span>
There are no items in your cart. Continue shopping.
</span>
</div>
}
else
{
<ul class="cart-dropdown">
<li>
<div class="cart-items cart-caption">
<ul>
#foreach (var i in Model.CartItems)
{
<li id="list-item-#i.item.ItemID">
<div class="container-fluid item-wrap" style="position: relative">
<div class="item-remove">
<a href="#" class="RemoveLink"
data-id="#i.RecordID" data-itemid="#i.item.ItemID">
x
</a>
</div>
<div class="col-md-2 item-img">
<div class="row-cart">
<img alt="" id="cartImg" height="71" width="75" src="#i.item.ImageUrl">
</div>
</div>
<div class="col-md-5 item-info">
<div class="row-cart">
<div class="brand-name">
<a href="#" class="brandName">
#i.item.BrandName
</a>
</div>
<div class="product-name">
<a href="#" class="productName">
#i.item.ItemName
</a>
</div>
<div class="product-qty">
<p class="productQTY" id="item-count-#i.item.ItemID">
#i.Count x #i.item.ItemPrice
</p>
</div>
</div>
</div>
<div class="col-md-5 price-info">
<div class="row-cart" style="margin-top: 10px">
<div class="col-md-6">
<div class="row-mrp">
<span class="cartItemPrice" id="item-total-#i.item.ItemID">
Rs #(#i.Count * #i.item.ItemPrice)
</span>
</div>
</div>
</div>
</div>
</div>
</li>
}
</ul>
</div>
</li>
<li class="clearfix">
<div class="col-md-6">
<div class="row-cart sub-cost" style="background: #fff; margin-left: -10px; margin-right: 0">
<p>
Sub Total :
<span style="float: right">
Rs
<span class="ng-binding"></span>
</span>
</p>
<p>
Delivery Charge :
<span qa="delChargeMB" style="float: right">Free</span>
</p>
</div>
<div class="row-cart cart-chkout-btn">
<button type="button">View Basket & Checkout</button>
</div>
</div>
</li>
</ul>
}
</div>
This html is the partial view that is initially rendered when user clicks a button to view the cart-items. So when user clicks on 'remove an item' button on this partial view, an ajax call is sent to server to remove an item from the cart-items and on success, load the UI again by rendering this partial view once again with new values from the database.
All this is working fine for the first iteration of the deletion of an item from the cart-item list. But when I'm deleting an item again as a second deletion, code is running twice. I'm guessing this is because <div class="container-cart"> is rendered twice on the page as after the first deletion, I can see it on the live DOM inside the browser that <div class="container-cart"> is encolsed inside another <div class="container-cart"> and then the normal elements are rendered in sequence. I'm guessing maybe that's why javaScript is rendered twice or running twice.
Please suggest what you think about it and help me resolve it.
Thanks in advance
After deletion of an item try to use location.reload(); instead of hitting the MVC action method again!

AngularJS - JQuery News Ticker - After moving news the javascript function doesn't get called

This is an awkward problem, which will be better explained by looking at the live demo. Basically I have a news box populated with ng-repeat using Angular. Then I am using a jquery plugin called news ticker which allows the news headlines to move around. The first time you land on the page the news items are in their proper spots and they call the function accordingly. After moving them up or down, they stop calling the function, set a breakpoint in the code and after moving the breakpoint is never hit.
Edit - After researching this further I have found that it is because the elements need to be compiled using $compile after they're re added. However following some examples I have not gotten this to work. I need a way of compiling after a move event with this plugin.
Live demo
Angular Script for with function that should be called.
$scope.UpdateNews = function (item,number) {
console.log(item + ' ' + number);
switch (item)
{
case 'General':
$scope.NewsCast.General.Body = $scope.News.GeneralNews[number].Text;
break;
}
};
What the HTML looks like with the news boxes
<script src="http://www.jqueryscript.net/demo/Responsive-jQuery-News-Ticker-Plugin-with-Bootstrap-3-Bootstrap-News-Box/scripts/jquery.bootstrap.newsbox.min.js" type="text/javascript"></script>
<div class="row">
<div class="col-md-6 col-lg-3">
<div class="panel panel-default">
<div class="panel-heading"> <span class="glyphicon glyphicon-list-alt logo-inverse pull-left"></span><b> General News</b></div>
<div class="panel-body">
<div class="row">
<div class="col-xs-12">
<ul class="demo1" style="overflow-y: hidden; height: 280px;" ng-model="Idk">
<li style="" class="news-item text-left" ng-repeat="item in News.GeneralNews"><strong>{{item.DateValue | date: "MMM dd yyyy"}}</strong> {{item.Preview}}<a class="FakeClickable" ng-click="UpdateNews('General',item.index)" data-target="#GeneralModal" data-toggle="modal">Read more...</a></li>
</ul>
<div ng-if="Width>768">
<div ng-include="'../pages/Modals/General/GENERAL_INLINE.html'"></div>
</div>
</div>
</div>
</div>
<div class="panel-footer"> </div>
</div>
</div>

ng-repeat: prevent changing of information in previous panels

So, the issue is:
I have an HTML structure here:
<div class="container-fluid" ng-click="goto(item.title)" ng-repeat="item in someResponse" data-toggle="collapse" data-parent="accordion"
data-target="#collapseone_{{ $index }}" aria-expanded="false" aria-controls="#collapseone">
<div class="panel-group" id="accordion">
<div class="panel panel-info">
<div class="panel-heading">
<div class="wrap">
<img class="img" ng-src="{{item.img_url}}">
<p>{{item.title}}</p>
<p>{{item.price | currency}}</p>
<p>{{item.summary}}</p>
</div>
</div>
<div id="collapseone_{{ $index }}" class="panel-collapse collapse" ng-model="collapsePanel">
<div class="panel-body">
<div>
<p>{{IdResponse.price | currency}}</p>
<p>{{IdResponse.title}}</p>
<img class="img" ng-src="{{IdResponse.img_url}}">
<p>{{IdResponse.summary}}</p>
<p>Bathrooms:{{IdResponse.bathroom_number}}</p>
<p>Bedrooms:{{IdResponse.bedroom_number}}</p>
<input type="button" value="favourites" ng-click="goto1()">
</div>
</div>
</div>
</div>
</div>
And its controller:
angular
.module('PropertyCross')
.controller('searchResultsCtrl', ['$scope', '$http', '$location', 'myService',
function ($scope, $http, $location, myService) {
$scope.someResponse = myService.getData();
console.log($scope.someResponse);
$scope.goto = function (id) {
myService.setID(id);
console.log(id);
$scope.IdResponse = myService.getID();
console.log($scope.IdResponse);
};
$scope.goto1 = function () {
myService.setFav($scope.IdResponse);
}
}
]);
When I click on one collapse panel I have the right data coming from the back, but the problem appears when I try to open two or more panels. As a result I have the same things on all opened panels.
How can I prevent the changing of information in previous panels?
You could have the service push the data back into to the someResponse model. That way all of the price and detail information just extends the general listing. and since it is living within your ng-repeat the two-way binding will render the info.
Just change this code to this.. I'm not sure if the id below is a unique id from a database or the id within the array which is part of the response. if you have both you can use this code...
$scope.goto = function (id, arrayIndex) {
myService.setID(id);
console.log(id);
$scope.someResponse[arrayIndex].IdResponse = myService.getID();
console.log($scope.someResponse[arrayIndex].IdResponse);
};
So, you are storing the information into an object within the original model. What you were doing was storing everything in one data model. So, whenever you updated it, the two way binding updated and cascaded to the two references (in both expanded panels).
Next, you would update your ng-repeat and ng-click to this:
<div class="container-fluid"
ng-click="goto(item.title, index)"
ng-repeat="(index, item) in someResponse"
data-toggle="collapse" data-parent="accordion"
data-target="#collapseone_{{ $index }}"
aria-expanded="false" aria-controls="#collapseone">
and finally update the curly braces in the panels to something like this:
<div id="collapseone_{{ $index }}"
class="panel-collapse collapse" ng-model="collapsePanel">
<div class="panel-body">
<div ng-show="item.IdResponse">
<p>{{item.IdResponse.price | currency}}</p>
<p>{{item.IdResponse.title}}</p>
<img class="img" ng-src="{{item.IdResponse.img_url}}">
<p>{{item.IdResponse.summary}}</p>
<p>Bathrooms:{{item.IdResponse.bathroom_number}}</p>
<p>Bedrooms:{{item.IdResponse.bedroom_number}}</p>
<input type="button" value="favourites" ng-click="goto1()">
</div>
</div>
</div>
And I added an ng-show="item.IdResponse" so that the formatting wont show up until there is an object returned from the server.
I hope this answers your question.

angularjs how to set text inside element based on textbox input

My code is:
<div ng-controller="myCtrl">
<div class="row">
<div class="col-md-4 col-sm-3">
<checked-input ng-scope="$eventID"></checked-input>
</div>
<div class="col-md-4 col-sm-3">
<output ng-scope="$postbackOutput">***This is where I want the text typed in the textbox to go***</output>
</div>
<div class="col-md-3 col-sm-3">
<a ng-click="generateURL($eventID)" class="btn-plus">
<span class="glyphicon glyphicon-plus"></span>
</a>
</div>
</div>
</div>
So what I'm trying to do is get that $eventID that's inside the first column div, then pass it as an argument to the function call generateURL() when the link in the <a> tag is clicked in the third column. Inside the controller I have:
app.controller('postbackCtrl', function($scope) {
$scope.generateURL = function(eventID) {
$scope.postbackOutput = eventID;
}
});
But it doesn't seem to be setting the text in the <output> correctly. Could anyone help? I've just started out with angular so it's a bit confusing.
You can just bind the var to the view with handlebar brackets:
<output ng-scope="$postbackOutput">
{{ postbackOutput }}
</output>
Here is a working plunkr

JQuery .on("click"... works intermitently

I have a piece of code:
$("body").on("click", ".reply-button", function(){
alert("test");
});
That is suppose to alert me when I click on an element that is generated on the fly (it is not part of the DOM when this code is executed).
Sometimes it works just as it's suppose to. I click the button and a little alert pops up. However, other times it stop working. Nothing I bind to it will work. If I bind to the container div (also generated on the fly), it does work, but not if I change the handler to incorporate button.
I am asking for what could be the possible reasons for this error? I do not know how to go about debugging this. My first guess was that it was something due to stopImmediatePropagation or stopPropagation but I couldn't find that being used in the same area.
Does anyone have any idea on how I should go about debugging this?
EDIT:
How is the DOM being generated?
I get the HTML from a template that's hidden.
var html = $("#template").html();
Then I append the template to a div container
$("#container").append(html);
EDIT2:
Here is the template being pulled:
<div id="tweets-container" class="feed-wrapper">
</div>
<div id="tweet-template" style="display:none;">
<!-- Tweet 1 -->
<div class="tweet animated" data-scannedTweetId="s_id">
<!-- User -->
<div class="tweet-user">
<!-- User picture -->
<img class="tweet-user-picture" src="s_twt_owner_profile_img_url" />
<!-- User info -->
<div class="tweet-user-info">
<!-- User name -->
<div class="tweet-user-info-name">
s_twt_owner_name (#s_twt_owner_sn)
</div>
<!-- User biography -->
<div class="tweet-user-info-biography">
s_twt_owner_desc
</div>
</div>
</div>
<!-- User statistics (following, followers, and tweets) -->
<span class="tweet-statistics animated">
<div class="following">
<div class="statistic-count">s_twt_owner_num_following</div>
<div class="statistic-label">following</div>
</div>
<div class="followers">
<div class="statistic-count">s_twt_owner_num_follower</div>
<div class="statistic-label">followers</div>
</div>
<div class="tweets">
<div class="statistic-count">s_twt_owner_num_twt</div>
<div class="statistic-label">tweets</div>
</div>
</span>
<!-- Tweet bars/graph -->
<div class="side-information animated">
<div class="bar-wrapper">
<!-- Actual bars -->
<div class="bars">
<div class="bar big-bar bar-green" style="height: tqes_heightpx; background: tqes_color;" data-toggle="tooltip" data-placement="top" title="tq_engage_score"></div>
<div class="bar bar-yellow" style="height: tqrs_heightpx; background: tqrs_color;" data-toggle="tooltip" data-placement="top" title="tq_relevancy_score"></div>
<div class="bar bar-light-green" style="height: sks_heightpx; background: sks_color;" data-toggle="tooltip" data-placement="top" title="s_klout_score"></div>
<div class="bar bar-green" style="height: sls_heightpx; background: sls_color;" data-toggle="tooltip" data-placement="top" title="s_legitimacy_score"></div>
<div class="bar bar-gray" style="height: tqgs_heightpx; background: tqgs_color;" data-toggle="tooltip" data-placement="top" title="tq_geography_score"></div>
</div>
<!-- Labels that correspond with each bar -->
<div class="bar-labels">
<div class="bar-label big-bar-label" data-toggle="tooltip" data-placement="bottom" title="Score">tq_engage_score</div>
<div class="bar-label-icon" style="font-size: 12px; color: #000;" data-toggle="tooltip" data-placement="bottom" title="Relevancy">
<i class="fa fa-bullseye"></i>
</div>
<div class="bar-label-icon" data-toggle="tooltip" data-placement="bottom" title="Influence">
<i class="fa fa-users"></i>
</div>
<div class="bar-label-icon" data-toggle="tooltip" data-placement="bottom" title="Legitimacy">
<i class="fa fa-check-circle"></i>
</div>
<div class="bar-label-icon" data-toggle="tooltip" data-placement="bottom" title="Geography">
<i class="fa fa-map-marker"></i>
</div>
</div>
</div>
<!-- Notes below the bars/graph -->
<div class="explanations">
<!-- Note below the bars/graph -->
<div class="explanation">
<div class="explanation-check"><i class="fa fa-first-comment"> </i>
<div class="explanation-text">
comment_one
</div>
</div>
</div>
<!-- Note below the bars/graph -->
<div class="explanation">
<div class="explanation-check"><i class="fa fa-second-comment"> </i>
<div class="explanation-text">
comment_two
</div>
</div>
</div>
</div>
</div>
<!-- Tweet score -->
<div class="score-wrapper">
<div class="score animated">tq_engage_score</div>
</div>
<!-- Tweet content -->
<div class="tweet-content">
s_twt_text
</div>
<!-- Time since tweet was posted -->
<div class="tweet-time-elapsed">
s_twt_time
</div>
<!-- Area below tweet with reply textarea and buttons -->
<div class="tweet-reply-section animated">
<!-- Reply textarea -->
<textarea class="tweet-reply animated">#s_twt_owner_sn </textarea>
<!-- Buttons -->
<div class="buttons animated">
<!-- Small buttons on top of reply button -->
<div class="top-buttons">
<span class="character-count">
</span>
</div>
<!-- Reply button -->
<div class="reply-button">
Reply <i class="fa fa-reply"></i>
</div>
</div>
</div>
</div>
</div>
JavaScript:
/**
* Add a tweet to the feed.
*/
function _addTweetToFeed(tweet, keywords) {
/** Get the tweet template */
var tweetHtml = $('#tweet-template').html();
// add score heights and colors properties to the tweet
tweet = _setScoreBars(tweet);
/** Linkify elements of the tweet */
tweet.s_twt_text = twitterify(tweet.s_twt_text); // the tweet
tweet.s_twt_owner_desc = twitterify(tweet.s_twt_owner_desc);
// fix search terms to be highlighted
tweet.s_twt_text = _highlightSearchTerms(tweet.s_twt_text, keywords); // the tweet
tweet.s_twt_owner_desc = _highlightSearchTerms(tweet.s_twt_owner_desc, keywords);
// change from twitter links to readable links
tweet = _fixTweetLinks(tweet);
/** Make numbers readable */
tweet.s_twt_owner_num_following = abbrNum(tweet.s_twt_owner_num_following, 1);
tweet.s_twt_owner_num_follower = abbrNum(tweet.s_twt_owner_num_follower, 1);
tweet.s_twt_owner_num_twt = abbrNum(tweet.s_twt_owner_num_twt, 1);
/** Loop through the properties of tweet object and populate tweetHtml with them */
for (var prop in tweet) {
if (tweet.hasOwnProperty(prop)) {
tweetHtml = _replaceAll(tweetHtml, prop, tweet[prop]);
}
// add comments
tweetHtml = _addComments(tweet, tweetHtml);
/** If both location and url are not present, remove the comma */
if (!(tweet.s_twt_owner_loc && tweet.s_twt_owner_url)) {
$('#url_comma').html('');
}
}
$('#tweets-container').append(tweetHtml);
}
"Sometimes it works just as it's suppose to" this line alone suggests that you run your code prior to DOM creation. sometimes your browser creates the dom fast enough and the handler is being attached to the body, and sometimes your javascript runs first and it isnt being attached. wrap your code in this:
$(function(){
$("body").on("click", ".reply-button", function(){
alert("test");
});
});
Does anyone have any idea on how I should go about debugging this?
Sometimes it's best to pull out a tiny portion of code, and see if it works in isolation. For example: http://jsfiddle.net/6v7z9fak/
js:
$("body").on("click", ".reply-button", function(){
alert("test");
});
html:
<button type="button" class="reply-button">Reply</button>
As you'll see, it works fine. So you can be confident that the error is not in that bit of code alone. It is either another part of the code, or how the parts are interacting together, or something else. Now slowly add more code, test, and see where it breaks.

Categories