$location does not navigate on first ng-click callback - javascript

Something weird is going on in my AngularJS application. I have a view which has a list of anchor tags bound to an array of objects (I'm using ng-repeat to render the list). Each one of the anchor tag has an ng-click bound to a method on the controller. The method is as follows:
$scope.onSiteSelected = function ($event, site) {
$event.preventDefault();
$.ajax({
url: '/Site/GetSiteMap/' + site.Id,
success: function (response) {
if (response && response.length > 0) {
menuManager.setSiteMap($scope.$root.menu, response[0]);
var url = response[0].Children[0].Settings.Url;
$location.path(url);
}
}
});
}
The url var is being initialized to the correct value every time. But, when I click on the anchor tag the first time, $location.path(url) does nothing, and when I click it for a second time, it does navigate to the target url.
UPDATE:
Ok I got it working by using the $http service as follows:
$scope.onSiteSelected = function ($event, site) {
$event.preventDefault();
var address = '/Site/GetSiteMap/' + site.Id;
$http.get(address)
.success(function (response) {
if (response && response.length > 0) {
menuManager.setSiteMap($scope.$root.menu, response[0]);
var url = response[0].Children[2].Settings.Url;
$location.path(url);
}
});
}
Does it really make a difference if I used $,ajax or $http? I thought the two can be used interchangeably...?

No you cannot use them interchangibly, $.ajax is jQuery whereas $http is angular's http service.
Resist the urge to use jQuery as there is almost always a way to do it in the angular way.
That being said, if you do something outside of angular world, (mostly callbacks didn't occur from angular), you need to apply the changes to force a digest cycle.
$.doSth(function callback() {
$scope.$apply(function () {
// your actual code
});
});
Please read the most voted answer in "Thinking in AngularJS" if I have a jQuery background? . This would guide you to avoid using jQuery where there is an alternative.

Related

Call method when dynamic element is in DOM

I use $http service to get data and generate DOM elements.
How can I in jQuery/AngularJS call a method (example .slideToggle()) on dynamic element? I need to do this when page is loaded (not on click event etc.).
To do this one $('#test').slideToggle() (#test is generated element) i need use timeout.
It's difficult to know for sure from your description, but if you're creating the element from data you retrieve remotely, you should ensure that element's creation/insertion are completed before you attempt to scroll to it.
The following code is an example of how you may do this:
$http({
method: 'GET',
url: '/someUrl'
})
.then(createAndInsertYourElement)
.then(scrollToElem);
function createAndInsertYourElement(data) {
var $elem = $('<div id="test">' + data.whateva + '</div>');
$('#someElement').append($elem);
return $elem;
}
function scrollToElem($elem) {
$elem.slideToggle();
}
Note the .thens. These are an option because Angular's $http returns a promise. If you're not familiar with promises, yet, they are awesome, and you should check 'em out: http://www.dwmkerr.com/promises-in-angularjs-the-definitive-guide/

Change angularjs code to work for jquery pop-up

Hi I don't know angularJS yet I have a task in that. There is dashboard which is designed in angularJS. Now, in that there is link which will
open a pop-up. I have given a task to change that link to another pop-up but that pop-up is in jQuery. So, for me it is quite difficult to understand how to
change this.
I have a xml file where all the label in html are defined. This is the label from where the link is coming.
<subcolumn type="a" ngclick="decisioncomp();" styleName="proccheader labe1padding" text="Complete : " uniqueID="data31" />
Now, in the controller file of the same there is a function defined.
// complete link click
$scope.decisioncomp = function () {
if ($scope.data31 != "") {
ModalService.showModal({
templateUrl: "ChartpagePopup/Complete.html",
controller: "Complete"
}).then(function (modal) {
modal.close.then(function (result) {
$scope.customResult = "All good!";
});
});
}
else
alert($scope.waitingalert);
};
So, I came to know from here the link is going to html and controller. Now, I thought that if changed this ModalService.showModal to not to take controller
or if I send controller empty and replace my html with this html, my work should be done. So what I did is I changed in the Script file for that where this
funtion is defined.
I commented out line where it says that controller can't be empty.
self.showModal = function(options) {
// Create a deferred we'll resolve when the modal is ready.
var deferred = $q.defer();
// Validate the input parameters.
var controllerName = options.controller;
if (!controllerName) {
//deferred.reject("No controller has been specified.");
//return deferred.promise;
}
But then the link itself is not opening. I don't know where else to change. I am stuck here. Please someone help me.

Add Content To DOM AFTER AngularJS Has Completed Asynchronous Loading

I have angular code that fetches 8 json files asynchronously each via $http.get. This is called using ng-init="someFunct()" in a template code that is attached. Everything works great including filtering when a user types into an input text box. Filtering is especially important to my application.
To make filtering even better, I extract keywords from the said json files which I then wrap with <span class="tag" ng-click="filterWith='kywd'">{{kywd}}</span> in the hope that a user can click on the tags instead of type. This ONLY works if I embed the tags statically - in the real application I cannot know the keywords in advance. If I insert dynamically via $("#someContainerID").append(TAG_HTML_CODE) or similar it NEVER works!
In a nutshell this is what I need to achieve:
1) Dynamically inject multiple (in hundreds) such tags into DOM;
2) Inject the tags ONLY after everything else has loaded and compiled - but especially after the json files have been read and keywords extracted;
3) The tags that I inject need to respond to something like ng-click="filterWith='some_keyword'"
If there was a way to tell when AngularJS has finished all other processing - how great this would be! I have read everywhere and it seems so cryptic and confusing - pls HELP!
I have even tried the following code to no avail:
$timeout(function () {
$scope.$apply(function () {
//code that works on the keywords - works perfect!
var filterRegex = /\s*([\w\d.%]+)\s*/i;
var dom_elem = angular.element(document.querySelector("#filter_tags"));
dom_elem.html("");
for (var m = 0; m < tags.length; m += 1) {
var match = filterRegex.exec(tags[m][0]);
if (match != null) {
dom_elem.append($compile("<span data-ng-model=\"filterWith\" data-ng-click=\"filterWith='" + match[1] + "'\" title=\"" + tags[m][1] + "\" class=\"sk3tag clk\">" + match[1] + "</span>")($scope));
}
}
});
}, 10000, false);
}
EDIT: Narrowed the scope of my challenge to mainly one!
The bigger challenge for me is how to enable ng-click in the dynamically injected code and how to do it right.
Use Promise.all() to trigger when everything is loaded.
Earlier I had asked the question above. Somebody suggested I read further on directives instead. I did, fairly well. I came up with the following solution, to use click events on html code injected dynamically to DOM. I thank truly God for helping me figure it out, eventually. I no longer need to wait for the asynch data, whenever it comes and hence updates the model, my html tags are updated automatically - MVC magic! It seems to work great!
ANGULAR
//excerpt
myNgApp.controller('ctlTodayLatest', ['$scope', '$timeout', '$compile', '$http', function () {
$http.get('/filtertags.json').then(function (response) {
$scope.filterTags = response;
},
function (response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log(response);
}
);
}]);
myNgApp.directive("myFilterTag", function () {
return {
template: "<span data-ng-repeat=\"tag in filterTags\" title=\"{{tag[0]}}\" class=\"mytag clk\" ng-click=\"filterWith(tag[0])\">{{tag[0]}}</span>",
link: function (scope, element, attrs) {
scope.filterWith = function (term) {
scope.fQ = term;
};
}
};
});
HTML
//excerpt
<div id="filter_tags" class="xip2 TAj" my-filter-tag></div>

jQuery in a wordpress template page

I am developing a tool for my Wordpress website using jQuery, I am quite new at this but what I'm trying to do is not that hard.
My script is enqueued, i've read that with the NoConflict mode i can't use $ so I use jQuery instead.
function Calculator()
{
var result = jQuery('result');
if (jQuery('day').value == "" || jQuery('month').value == "" || jQuery('year').value == "") {
return;
}
result.update('<span class="result">processing</span>');
jQuery('form').request({
onComplete: function(transport) {
result.hide();
result.update(transport.responseText);
new Effect.Appear(result, { duration: 0.5 } );
}
});
}
My problem is I got error everywhere :
update is not function
request is not function
etc...
There is something i'm obviously doing wrong but can't figure out what...
thanks a lot !
The errors you are seeing ("update is not function request is not function") describe the problem - those really are not jQuery functions.
It looks like you're trying to update an HTML element with ID or class "result". To do that, use .html():
var result = jQuery('.result'); // "." to select the element with class result
result.html('something');
For .request, it looks like you are trying to do a POST or GET of a form. If so, use .ajax(), .post(), or .get(). Note though you'll need to add a few more details, eg:
jQuery('form').ajax({
type: "POST",
url: someurl,
data: somedata,
onComplete: ...
});
Also, if your Calculator() function can be called while the page is loading, make sure it (or whatever calls it) is wrapped in document.ready:
jQuery(document).ready(function () {
...
});
An unrelated issue, to check the value of say a form input with class "day", you need to use:
jQuery('.day').val()
if you are fetching the value using class then you have to do it like this:
jQuery('.result').val()
or if using id use it like:
jQuery('#result').val()
in jquery we use .val() function to get value instead of value.
Is update, request exists in jquery?
you can use like this rather than writing again and again.
var j = jQuery.noConflict();
j(".result").html("<span>Processing..</span>");

Angularjs click row if the data is available

I'm new to JavaScript so I am not sure what is possible. I am using AngularJS as my frontend application.
I've a clickable table(rows) its pretty much a table inside a table (collapisble table)
I'm trying to click the first row of the table if the data is available so I wrote this function
$scope.clicker = function(){
if (!$scope.first || !$scope.second){
setTimeout($scope.clicker, 500)
}
$(".clickableRow").first().click()
}
This pretty much checks if the values first and second is not null, if not then click the first row. This WOULD work sometimes but almost every time I get this error '
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.4.3/$rootScope/inprog?p0=%24digest
I am not sure what this means. Any help would be nice.
Using $q.all you can pass in multiple $http requests in an array.
You can use .then on the q.all() method and get a callback when they're all done.
$scope.$watch(
function() {
return $route.current;
},
function(newValue) {
if (newValue) {
$scope.url = newValue.$$route.originalPath;
if($scope.url == '/loadTestForm') return;
$scope.neustaridParam = newValue.params.neustarid;
$q.all([
$http.get('/corecase/browserKPI/'+$scope.neustaridParam).success(function(response){
$scope.browserKPI = response;
}),
$http.get('/corecase/serverKPI/'+$scope.neustaridParam).success(function(response){
$scope.serverKPI = response;
}),
$http.get('/corecase/info/'+$scope.neustaridParam).success(function(response){
$scope.corecaseinfo = response;
})
]).then(function(){
$scope.selectTableRow(0, 1000); //I'd advise not hardcoding the first row's data here. You can do something like this instead: $scope.storeDataModel.storedata[0].id, scope.storeDataModel.storedata[0].storeId
});
}
}
);
If the only purpose behind the click event is to show or hide then you can potentially skip the click event all together. Put a "ng-show" in your tr (or any other element you want to show) and simply set a scoped variable equal to whatever is referencing your data. If you have data then your ng-show will be true and it will show. This is also assuming that your data is undefined or null until it is available, if not just set it to false.
In view:
<tr ng-show="checkData"></tr>
In controller:
$scope.checkData = data;

Categories