Angular v1+: loading different area in page by angularjs - javascript

suppose when first time web site load then i need to load left and top menu.
both menu will load independently and so anyone may load and show first.
so tell me the trick which i need to apply to show both left and top menu at same time if top or left menu load first. some how i need to show both the menu at same time.
tell me what code i need to change in below. below code is just a sample code and not tested.
app.service("TopMenuService", function ($http) {
this.getTopMenu = function () {
debugger;
return $http.get("/employee/getTopMenu");
};
});
app.service("LeftMenuService", function ($http) {
this.getLeftMenu = function () {
debugger;
return $http.get("/employee/getLeftMenu");
};
});
app.controller("EmpCtrl", function ($scope, TopMenuService,LeftMenuService) {
GetTopMenu();
GetLeftMenu();
function GetTopMenu() {
debugger;
var _getTopMenu = EmployeeService.getTopMenu();
_getTopMenu.then(function (topmenu) {
$scope.topmenu = topmenu.data;
}, function () {
alert('Data not found');
});
}
function GetLeftMenu() {
debugger;
var _getLeftMenu = EmployeeService.getLeftMenu();
_getLeftMenu.then(function (leftmenu) {
$scope.leftmenu = leftmenu.data;
}, function () {
alert('Data not found');
});
}
});

What about a load menus procedure controlled by a promise?
Note on $q.all() Promises in AngularJs are handled by the $q service. Promises are used to synchronize the execution of tasks on concurrent envirorments, AngularJs's $q.all receives a list of various promises and fires the then callback when all promises on the list gets resolved, in this case, the two promises are the $http.get() of each menu, it's an async promise case so that when the response is sent, it resolves the promise and fires the then() registered callback, eventually will fire $q.all() as well.
app.controller("EmpCtrl", function ($scope, $q, TopMenuService, LeftMenuService) {
$scope.shouldDisplayMenus = false;
LoadMenus().then(function () {
$scope.shouldDisplayMenus = true;
});
function LoadMenus() {
return $q.all([
GetTopMenu(),
GetLeftMenu()
]);
}
function GetTopMenu() {
debugger;
var _getTopMenu = EmployeeService.getTopMenu();
_getTopMenu.then(function (topmenu) {
$scope.topmenu = topmenu.data;
}, function () {
alert('Data not found');
});
return _getTopMenu;
}
function GetLeftMenu() {
debugger;
var _getLeftMenu = EmployeeService.getLeftMenu();
_getLeftMenu.then(function (leftmenu) {
$scope.leftmenu = leftmenu.data;
}, function () {
alert('Data not found');
});
return _getLeftMenu;
}
});

If you want to make sure that only after both requests complete you proceed - use $q.all:
app.controller('EmpCtrl', function($scope, TopMenu, LeftMenu, $q) {
$q.all([TopMenu.get(), LeftMenu.get()]).then(function(both) {
var top = both[0];
var left = both[1];
});
});

Related

window.onunload event wont fire inside AngularJS controller

I have the following command inside an AngularJS controller
window.onunload = function () {
connection.invoke("RemoveUser", playerName);
}
It's weired because I have a pure JS where this statement works well, so outsite an angularJS controller when I close the tab or the window, it fires and do its job, but when I put this inside a controller, it doesn't fire. Any ideas?
Full script bellow
angular.module("mathGameApp", []).controller("mathGameCtrl", function ($scope) {
// Current player name
$scope.playerName;
$scope.welcomeIsVisible = true;
$scope.gameAreaIsVisible = false;
$scope.countdownIsVisible = false;
// Create connection
const connection = new signalR.HubConnectionBuilder()
.withUrl("/MathGame")
.configureLogging(signalR.LogLevel.Information)
.build();
// Get math challenge
connection.on("GetChallenge", data => {
// Bind challenge
$scope.expression = data.expression + " = " + data.possibleResult;
$scope.$apply();
});
// Receive and bind score
connection.on("ReceiveScore", data => {
$scope.score = data;
$scope.$apply();
});
// Rise alert
connection.on("RiseAlert", data => {
alert(data);
})
// Get status that the player was added to game room
connection.on("AddedToGameRoom", data => {
$scope.welcomeIsVisible = false;
$scope.gameAreaIsVisible = true;
$scope.$apply();
})
connection.on("ChallengeFinished", data => {
$scope.counter = 5;
$scope.countdownIsVisible = true;
$scope.$apply();
let interval = setInterval(function () {
if ($scope.counter == 0) {
$scope.countdownIsVisible = false;
$scope.buttonIsDisabled = false;
$scope.$apply();
clearInterval(interval);
connection.invoke("RefreshChallenge");
}
$scope.counter--;
$scope.$apply();
}, 1000);
})
// rise answer Correct/Wrong
connection.on("RiseAnswer", data => {
$scope.buttonIsDisabled = true;
$scope.expression = data;
$scope.$apply();
console.log($scope.buttonsDisabled);
console.log($scope.expression);
})
// Request the user to be added to game room
$scope.enterGame = function (playerName) {
connection.invoke("EnterGame", playerName);
}
$scope.answerQuestion = function (playerName, answer) {
connection.invoke("AnswerQuestion", {
"playerName": playerName, "isCorrect": answer
});
}
// Open connection
connection.start().then(() => {
}).catch((err) => {
alert(err.toString())
});
window.onunload = function () {
connection.invoke("RemoveUser", playerName);
}
})
Controllers should use the $onDestroy Life-Cycle Hook to release external resources.
app.controller("mathGameCtrl", function ($scope) {
̶w̶i̶n̶d̶o̶w̶.̶o̶n̶u̶n̶l̶o̶a̶d̶ ̶=̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶)̶ ̶{̶
this.$onDestroy = function () {
connection.invoke("RemoveUser", playerName);
}
})
For more information, see AngularJS $compile Service API Reference - Life-Cyle hooks.
Update
You can and should handle the 'unload' event through window.addEventListener(). It allows adding more than a single handler for an event. This is particularly useful for AJAX libraries, JavaScript modules, or any other kind of code that needs to work well with other libraries/extensions.
For more information, see
MDN Web API Reference - WindowEventHandlers.onunload
MDN Web API Reference - EventTarget.addEventListener()

AngularJS $destroy on $rootscope never gets called to cancel timeouts

I have the following code -
function initialize() {
var defer = $q.defer();
var deferTimer = $q.defer();
var cancelTimeout = $timeout(function() {
if (defer !== null) {
ctrlr.setProcessingParameters('XXX');
defer = ctrlr.openProgressBar();
deferTimer.resolve();
}
}, 1000);
deferTimer.promise.then(function() {
var cancelTimeout2 = $timeout(function() {
if (defer !== null) {
defer.resolve();
ctrlr.setProcessingParameters('Please Wait...');
defer = ctrlr.openProgressBar();
}
}, 4000);
});
//Process Backend service n resolbve defer....
}
// cancel the $timeout service
$rootScope.$on('$destroy', function() {
logger.log("cancelTimeout..timer..");
if (cancelTimeout) {
$timeout.cancel(cancelTimeoutProcess);
cancelTimeout = null;
}
});
// cancel the $timeout service
$rootScope.$on('$destroy', function() {
logger.log("cancelTimeout2..timer..")
if (cancelTimeout2) {
$timeout.cancel(cancelTimeout2);
cancelTimeout2 = null;
}
});
I do not see the loggers print or debugger gets into $destroy. Not sure what's happening here.
$rootScope gets destroyed when you close or leave the page. Everything will be gone then, so there's nothing to clean up at that time.
What you are looking for is $destroy on $scope instead,
$scope.$on('$destroy', function() {
logger.log("cancelTimeout..timer..");
if (cancelTimeout) {
$timeout.cancel(cancelTimeoutProcess);
cancelTimeout = null;
}
});
While in the controller, $scope.$on('$destroy'.. will be called when controller gets destroyed (and not the whole application) with which current $scope is associated.

Setting value of dropdown programmatically

I have a directive which I want to change the value of on a click event. This is the controller that the click event is being triggered (I have removed all irrelevant code) :
(function () {
"use strict";
//getting the existing module
angular.module("app")
.controller("teamsController", teamsController);
//inject http service
function teamsController($scope, $http, divisionService, $rootScope) {
$scope.divisions = divisionService.all();
var vm = this;
vm.teams = [];
vm.newTeam = {};
vm.editTeam = function (team) {
$rootScope.$broadcast('someEvent', [team.division]);
}
And here is where the event is being captured :
(function () {
"use strict";
//getting the existing module
angular.module("app")
.controller("divisionsController", divisionsController)
.directive("divisionDropdown", divisionDropdown);
//inject http service
function divisionsController($http, $scope, divisionService, $rootScope) {
$scope.divisions = divisionService.all();
$rootScope.$on('someEvent', function (event, selectedDiv) {
alert(selectedDiv);
$rootScope.selectedDivision = selectedDiv;
});
};
function divisionDropdown() {
return {
restrict: "E",
scope: false,
controller: "divisionsController",
template: "<select class='form-control' ng-model='selectedDivision' ng-options='division.divisionName for division in divisions' required>\
<option style='display:none' value=''>{{'Select'}}</option>\
</select>"
};
}
})();
And this is the divisionService, which I am using to populate the dropdown intially :
app.factory("divisionService", function ($http) {
var divisions = [];
var errorMessage = "";
var isBusy = true;
//matched to verb, returns promise
$http.get('http://localhost:33201/api/Divisions')
.then(function (response) {
//first parameter is on success
//copy response.data to vm.divisions (could alternatively use a foreach)
angular.copy(response.data, divisions);
}, function (error) {
//second parameter is on failure
errorMessage = "Failed to load data: " + error;
})
.finally(function () {
isBusy = false;
});
return {
all: function () {
return divisions;
},
first: function () {
return divisions[0];
}
};
});
But I am not able to get the selectedDivision in the dropdown to change on the click event. Can anybody tell me how do I refer to it and reset it? I am not that familiar with scoping in Angular so my usage of $scope and $rootScope is possibly where the issue lies.

Why is my object not updated in the view in Angular?

I have SignalR working in my application:
app.run(['SignalRService', function (SignalRService) {}]);
SignalRService:
app.service("SignalRService", ['$rootScope', function ($rootScope) {
var masterdataChangerHub = $.connection.progressHub;
if (masterdataChangerHub != undefined) {
masterdataChangerHub.client.updateProgress = function (progress) {
$rootScope.$broadcast('progressChanged', progress);
}
masterdataChangerHub.client.completed = function (result) {
$rootScope.$broadcast('taskCompleted', result);
}
}
$.connection.hub.start();
}]);
As you can see I throw an event when a SignalR method gets invoked. This all works fine. However, on 1 directive, my data won't get updated. Here's the code:
app.directive('certificateDetails', ['CertificateService', 'TradeDaysService', 'DateFactory', function (CertificateService, TradeDaysService, DateFactory) {
return {
restrict: 'E',
templateUrl: '/Certificate/Details',
scope: {
certificateId: '=',
visible: '=',
certificate: '=',
certificateSaved: '&'
},
link: function (scope, element, attributes) {
scope.certificateFormVisible = false;
scope.showCancelDialog = false;
scope.splitCertificateFormVisible = false;
scope.partialPayoutFormVisible = false;
scope.$on("taskCompleted", function (evt, response) {
console.log(response);
CertificateService.getCertificateById(scope.certificate.Id).then(function (response) {
scope.certificate = response;
});
});
scope.$watch('visible', function (newVal) {
if (newVal === true) {
scope.showButtonBar = attributes.showButtonBar || true;
if (scope.certificateId) {
getCertificateById();
}
}
});
function getCertificateById() {
CertificateService.getCertificateById(scope.certificateId).then(function (response) {
scope.certificate = response;
});
};
}
}
}]);
The weird thing is, when I have my console open (I use Chrome) on the network tab, I can see that the directive makes a request to the right URL with the right parameters. Also, when the console is open, my data is updated in the view. However, and this is the strange part, when I close the console, nothing happens! It doesn't update the view..
I have also tried to put the code inside the taskCompleted event in a $timeout but that doesn't work either.
Could someone explain why this happens and how to solve this problem?
EDIT I
This is how the getCertificateById looks like in my CertificateService
this.getCertificateById = function (id) {
var promise = $http.post('/Certificate/GetById?id=' + id).then(function (response) {
return response.data;
});
return promise;
};
Handling SignalR events will execute out of the Angular context. You will need to $apply in order to force digest for these to work. I'd try to call $apply on $rootScope after the $broadcast:
var masterdataChangerHub = $.connection.progressHub;
if (masterdataChangerHub != undefined) {
masterdataChangerHub.client.updateProgress = function (progress) {
$rootScope.$broadcast('progressChanged', progress);
$rootScope.$apply();
}
masterdataChangerHub.client.completed = function (result) {
$rootScope.$broadcast('taskCompleted', result);
$rootScope.$apply();
}
}
If this works then the issue definitely a binding issue between SignalR and Angular. Depending on what browser plugins you have installed, having the console open could trigger a digest for you.
On the sample listeners for this project (that binds SignalR and Angular), you can see that a $rootScope.$apply() is needed after handling on the client side:
//client side methods
listeners:{
'lockEmployee': function (id) {
var employee = find(id);
employee.Locked = true;
$rootScope.$apply();
},
'unlockEmployee': function (id) {
var employee = find(id);
employee.Locked = false;
$rootScope.$apply();
}
}
So, I'd assume that you would need to do the same.

knockoutjs data saving UI issue

In my web app while I am updating some data I need to show some loading spinning gif in the web page.
This is my code.
This is my html code
<img src="../../../../Content/images/submit-gif.gif" class="hidegif" data-bind="visible: isWaiting"/>
<button data-bind="click: createNew">Save</button>
In my knockoutjs model I have this
self.isWaiting = ko.observable(false);
self.createNew = function () {
this.isWaiting(true);
$.getJSON("/Admin/Material/GetFolders", function (allData) {
this.isWaiting(true);
var mappedFolders = $.map(allData, function (item) { return new Folder(item); });
self.folders(mappedFolders);
this.isWaiting(false);
}).success(function () { this.isWaiting(false); }).error(function () { }).complete(function () { this.isWaiting(false); }); ;
};
I have property called isWaiting. Before I call the server I am setting it to true. In completion and successive method I am setting it back to false.
So based on that my spinning wheel should appear and disappear.
But this is not working.
Thanks In Advance
this will have another context inside the createNew and callback functions. You should use self instead of this for accessing view model's property:
self.createNew = function () {
self.isWaiting(true);
$.getJSON("/Admin/Material/GetFolders", function (allData) {
self.isWaiting(true);
var mappedFolders = $.map(allData, function (item) { return new Folder(item); });
self.folders(mappedFolders);
self.isWaiting(false);
}).success(function () {
self.isWaiting(false);
}).error(function () {})
.complete(function () {
self.isWaiting(false);
});
};

Categories

Resources