Angularjs click row if the data is available - javascript

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;

Related

Angular datatables with promise - reload line

I'm using angular-datatables with promise and everything work's fine. I have a lot of actions that can be done on each register (using angular $http resource) like change a status or something like that.
But, I need to reload datatable's data after every action even if i've edit just one line. And this process get's a little longer!
Is there any way to reload just the data that i've changed? For example, if I edit some line data I want just that line to be reloaded.
Forgive me if that's not a smart question, but I need to know if I can improve the performance of the actions over the table.
Here is my code!
DtOptions
vm.dtOptions = DTOptionsBuilder.fromFnPromise(function() {
vm.defer = $q.defer();
vm.mainService.getItems(idtask, flag, type).then(function(result)
vm.defer.resolve(result.data);
});
return vm.defer.promise;
})
.withOption('headerCallback', function(header) {
if (!vm.headerCompiled) {
vm.headerCompiled = true;
$compile(angular.element(header).contents())($scope);
}
})
.withPaginationType('full_numbers')
.withOption('createdRow', createdRow)
.withOption('deferRender', true)
.withDisplayLength(100)
.withOption('initComplete', function() { });
ReloadData function
function reloadData() {
var resetPaging = false;
vm.dtInstance.reloadData(function callback() {}, resetPaging);
}
After some execution over the table, I call the function reloadData().
Thanks for any help! And I'm sorry for my bad english.
don't reload the page just append the last added data to the array in ng-repeat
with simple javascript push
consider below as array to which we want add last added element. write this in "success block" so if there is confirmation of successful post then this will be added to current stack. same can be done for delete and update.
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi");\

Execute function only after display is fully rendered from ng-repeat not when ng-repeat reaches last index

I have a list being generated from ng-repeat and it's rendering a component tag on each iteration. And I'm giving each iteration a unique id utilizing the $index value.
That looks like this
<div ng-if="$ctrl.myArr.length > 0" ng-repeat="obj in $ctrl.myArr">
<myCustomComponentTag id="L1-{{$index}}" obj="obj"></myCustomComponentTag>
</div>
I need to run some jquery on these unique ids, which are populating just fine. The view will successfully show the tags to have ids of #L1-0, #L1-1, #L1-2
The snag is that my function running my jquery is executing before the view fully loads and the id values actually populate with the value of $index
My jQuery is searching for $(`#L1-${i}`) in a loop. If I store #L1-${i} in a string variable and output its value it will return '#L1-0'.
But '#L1-0' does not exist yet, as the view has not been fully populated. When I break on my function the ids on the elements only read L1-{{$index}} and have yet to populate.
I've read in several places to try this directive. This is still not working. It seems that just because my ng-repeat has reached its last element, it does not mean the view has populated and my ids are fully loaded and in place.
How can I execute my jQuery function only after the view is fully populated with my data?
Edit:
This is the jQuery function
jqFn= () => {
if (this.myArr.length > 0) {
for (var i: number = 0; i < this.myArr.length; i++) {
$(`#L1-${i}`).css({
/*
Add various styles here
*/
});
}
}
};
Perhaps you can try something like this
Disclaimer: I have found it one of the comments on the link that you referenced in the post.
The solution I used for this was a recursive function that set a timeout and searched for the id of the last object in the repeat statement until it exuisted. The id could not exist until the dynamic data from the $watch fully loaded in. This guaranteed all my data was accessible.
Code looked similar to this
setListener = (el, cb) => {
if ($(el).length) {
cb();
} else {
setTimeout(() => {
this.setListener(el, cb);
}, 500);
}
};

AngularFire - $firebaseArray can $add but not read

I feel like I must be missing something very basic. Here is a portion of my service:
angular.module('fire')
.constant('FIREBASE_URI', 'https://___.firebaseio.com/')
.factory('syncArraySvc', function(FIREBASE_URI, $firebaseArray) {
var buildingsUri = FIREBASE_URI + "buildings";
var buildings = $firebaseArray(new Firebase(buildingsUri));
console.log(buildings);
var getBuildings = function() {
return buildings;
};
var addBuilding = function(item) {
buildings.$add(item);
};
return {
getBuildings: getBuildings,
addBuilding: addBuilding
};
});
The console.log in the middle of that just returns an empty array. If I try to call the syncArraySvc.getBuildings() function from another controller, I also get an empty array. Somehow, $add(item) works, as does syncArraySvc.addBuilding(item). What am I missing?
If you look at $add $firebaseArray, It does create new item & add it into to $firebaseArray as like we have buildings. But as soon as you add item to ``$firebaseArray` it doesn't get added instantly. It get added when the $add promise get resolved.
I think you are doing correct thing, only you need call syncArraySvc.addBuilding(item) method on success of $add promise.
To make this approach you need to return a promise from the service method like
var addBuilding = function(item) {
return buildings.$add(item);
};
And then the caller function will take that promise and on resolve of it, he will call syncArraySvc.addBuilding(item) method that have assurity that items has added in buildings array.
syncArraySvc.addBuilding({foo: "bar"}).then(function(addedItem){
console.log(addedItem);
console.log(syncArraySvc.addBuilding(item)); //this will show you updated list
})
The other answers helped get me pointed in the right direction.
The API documentation has a code sample that doesn't seem to need the data to be wrapped in a promise:
var list = $firebaseArray(new Firebase(URL));
$scope.list = list;
However, it does point out that you can use the $loaded promise to be notified when the data is loaded. This is how I got it to work in my project:
syncArraySvc.getBuildings().$loaded(function(data) {
$scope.buildings = data;
});
I tried replicating this in a fresh project, and it consistently worked without the $loaded wrapper, like they show in the first example. It makes sense to me that the $loaded wrapper would be required. I don't understand how it could be working in the first example without it.
Try using a $timeout service inside the getBuildings function or rather when you call it. It probably takes a little while before data is returned.

Appending new results to an open jQuery autocomplete menu

I have an app in which I have multiple search sources. Previously, the users had to choose in what source to search in before searching. If they did not choose, the app would default to one of the options.
However, now they want to search in all the sources at the same time. This is fine enough, but the problem is that when one of the searches returns, it overwrites the previous search result. Pretty much expected behavior. What I basically want is to append the new results to the already open autocomplete menu, instead of overwriting the old results. Naturally, the autocomplete menu would have to empty when it closes.
I guess that this is possible to do, but what approach is the best? I could just have an array I guess, which I append results to and then overwrite _renderMenu to use this array instead of the items one that is passed to the function. Then empty said array at the close event.
Is this the best way to go though? Or is there a more elegant solution?
Some code:
Ok, so searchAction is called by jquery autocomplete eventually. In collection.search I do the ajax call, here the URL is created based in the this parameter, then respondWhithData is called and maps the search result to a proper format (ie value and label for the autocomplete menu). After reponse is called from respondWithData, jquery automagically renders the resultsmenu. Thus, I probably have to overwrite the reponse event function as well as the _renderMenu and possibly _renderItem, yes?
searchAction: function(searchTerm, collection, response){
var self = this;
$.when(collection.search(searchTerm, this)).then(function(data) {
self.respondWithData(data, response);
});
},
respondWithData : function(data, response) {
if (data.length > 0) {
var responseVal = _.map(data, this.mapData);
this.checkResponseCount(responseVal);
response(responseVal);
}
else {
response(this.emptyResult());
}
},
To be clear, the problem is not the multiple search itself, but rendering the asynchronos results. I want to render the first results that come back, and then appends the rest as soon as they are returned from the server.
Edit 2:
Just tried to edit ui.content in the autocompleteresponse event, but any edit does not take once it renders for some reason...
Edit 3: Ah, ui.content can only be modified directly, not changed. If I push every single change instead of concating two arrays ui.content shows what I want.
It works I guess, but its not perfect.
I can figure how looks your scenario but I'm guessing:
You should have like:
function search1() {
$.ajax({ ...
success: function(data) {
$('#myResultsDiv").html(data)
}
});
}
etc
Instead of overwritting the #myResultsDiv you need to Append the results like:
function search1() {
$.ajax({ ...
success: function(data) {
$('#myResultsDiv").append(data)
}
});
}
Edit: You can also do something like this:
var resultsArray = [];
var searchDone = 0;
var totalSearchs = 5; //assuming 5 searches
function search1() {
function search1() {
$.ajax({ ...
success: function(data) {
//APPEND data to resultsArray
searchDone++;
if(searchDone==totalSearch) //syncronize the 5 searchs before render
renderSearchs(resultsArray);
}
});
}

AngularJS Data One Step Behind

I'm tracking map coordinates using angularJS to update the data, however I've run into an odd issue where the data you see on the screen does not match the console statement.
zombie.controller("move", function($scope) {
io.on("location", function(data) {
console.log(data);
$scope.location = data.loc;
})
$scope.move = function(direction) {
$scope.title = ": Traveling";
io.emit("move", {direction:direction});
}
});
The console will log something like: Object {loc: "(59,30)"}
Let's assume the previous data was Object {loc: "(60,31)"}. My page will print (60,31) when the console is logging (59,30).
Also, when the page loads, the initial click will not display anything, but the console will log the correct data.
I have tried moving io.on('location') around inside the angular function, but if it's inside move() it will go bonkers and log like 15 times in a row and lag out. Outside the function is fine except for this issue. Any thoughts?
The code inside the io.on("location") is initiated by socket.io and Angular doesn't know about it, so its changes to the scope are not reflected until the next digest cycle. That is likely why the screen updates are always one step behind. Use $scope.$apply() to force a digest...
io.on("location", function(data) {
console.log(data);
$scope.location = data.loc;
$scope.$apply();
})
I agree with above answer but still in some cases like on input of text box,
you need to give timer to digest it properly.
setTimeout(function(){
$scope.apply();
}, 50);
This solves my problem.

Categories