Scope.$digest is not working in Jasmine - javascript

Trying to change the scope value, but not updated
Js File
$scope.$watch('match.Type', function (newValue) {
if ($scope.match.Type === 'NIGHT') {
$scope.value = false;
} else {
$scope.value = true;
}
});
Jasmine
it('should watches match type function', function() {
scope.match= {};
scope.match.Type = '';
describe('DAY', function() {
beforeEach(function() {
scope.match.Type = 'DAY';
scope.$digest();
});
it('DAY', function () {
expect(scope.value).toBe(true);
});
});
describe('NIGHT', function() {
beforeEach(function() {
scope.match.Type = 'NIGHT';
scope.$digest();
});
it('NIGHT', function () {
expect(scope.value).toBe(false);
});
});
})
;
Only one value updated, not the second value updated
I am for jasmine code and angularjs
Please help me to solve this problem

Related

using bootstrap 3.37 header dropdown menu and tranlsating jquery to knockoutJS

I was looking at this article to apply header menu with dropdowns in my mvc5 knockoutjs solution.
https://jdmdigital.co/news/codex/bootstrap-3-secondary-dropdown-menu/
The frontend it looks nice, and it is ok in my solution, however, I cant figure it out how to bind js section to work.
Now when I click on my dropdown parent item, nothing happens, because the js code is not working.
here is my setup of the js (knockoutjs) file.
define(['durandal/system', 'plugins/router', 'durandal/services/logger', 'knockout', 'common', 'plugins/dialog', 'durandal/binder', 'fastclick'],
function (system, router, logger, ko, common, dialog, binder, fs) {
var shell = {
activate: activate,
router: router,
};
// Make Dropdown Submenus possible
$('.dropdown-submenu a.dropdown-submenu-toggle').on("click", function (e) {
$('.dropdown-submenu ul').removeAttr('style');
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
// Clear Submenu Dropdowns on hidden event
$('#bs-navbar-collapse-1').on('hidden.bs.dropdown', function () {
$('.navbar-nav .dropdown-submenu ul.dropdown-menu').removeAttr('style');
});
//...
//...
//OTHER INIT METHODS (not in the scope for this question)
//#region Internal Methods
function activate() {
var result = registerRoutes();
//setRouteGuard();
if (window.cordova) {
window.document.addEventListener("deviceready", function () {
shell.refreshUserData(true);
shell.changeLanguage();
});
} else {
shell.refreshUserData(true);
shell.changeLanguage();
}
shell.isLoading.subscribe(function (newValue) {
//if something gone wrong
if (newValue) {
setTimeout(function () {
//shell.isLoading(false);
}, 10000);
}
});
if (router.activeInstruction().config.moduleId == "viewmodels/parentschedule") {
if (shell.isAnonymousUser() == true) {
shell.isClient(false);
shell.isEmployee(false);
}
else {
shell.isClient(true);
shell.isEmployee(true);
}
//console.log("test");
}
return result;
}
function route(r, moduleId, name, visible, alwaysVisible, role, condition) {
var self = this;
self.route = r;
self.moduleId = moduleId;
self.title = name;
self.visible = visible;
self.nav = true;
self.role = role;
self.condition = condition;
self.mouseover = ko.observable(false);
self.onhover = function () {
self.mouseover(!self.mouseover());
};
self.goToPage = function () {
router.navigate(this.hash);
};
self.alwaysVisible = alwaysVisible;
self.isTouched = ko.observable(false);
self.setTouched = function () {
self.isTouched(true);
return true;
}
self.setUnTouched = function () {
setTimeout(function () {
self.isTouched(false);
}, 200);
return true;
}
self.isActiveMenuItem = ko.computed(function () {
return router.activeInstruction() &&
router.activeInstruction().fragment.indexOf(self.route) > -1
});
return self;
}
//#endregion
});

Checking network connection status in Cordova and AngularJS

It's a basic question as I'm beginner in both Cordova and AngularJS.
I have an application with Cordova and AngulaJS and I want to check network connectivity using cordova-plugin-network-information in an angular way.
The below code works fine:
var app = angular.module('CordovaPluginTest', []);
app.run(['$rootScope', function ($rootScope) {
document.addEventListener('deviceready', function () {
document.addEventListener('online', toggleCon, false);
document.addEventListener('offline', toggleCon, false);
if (navigator.connection.type == Connection.NONE)
$rootScope.$apply(function () { $rootScope.isOnline = false; });
else
$rootScope.$apply(function () { $rootScope.isOnline = true; });
}, false);
function toggleCon(e) {
if (e.type == 'online')
$rootScope.$apply(function () { $rootScope.isOnline = true; });
else if (e.type == 'offline')
$rootScope.$apply(function () { $rootScope.isOnline = false; });
}
}])
But the below one does not work:
var app = angular.module('CordovaPluginTest', []);
app.run(['$rootScope', function ($rootScope) {
$rootScope.$on('deviceready', function () {
$rootScope.$on('online', function () { $rootScope.isOnline = true; });
$rootScope.$on('offline', function () { $rootScope.isOnline = false; });
if (navigator.connection.type == Connection.NONE)
$rootScope.isOnline = false;
else
$rootScope.isOnline = true;
});
$rootScope.$watch('isOnline', function (val) { alert('watch isOnline:'+val);})
}])
Why defining angular event listener doesn't work? In fact it doesn't get the event at all!
What is the correct way of doing this in angular?
For document DOM element Angular uses a wrapper ($document) and to bind relating events it relies on jQuery/jqLite.
So you can use $document.on("event-type",function( event ){ ... }); or angular.element(document).bind("event-type",function( event ){ ... }); to attach an handler to document.
But surely you can't use $rootScope.$on to listen to an event attached to document element.
Try this:
app.run(function($window, $rootScope) {
$rootScope.online = navigator.onLine;
$window.addEventListener("offline", function () {
$rootScope.$apply(function() {
$rootScope.online = false;
// $window.location.reload();
});
}, false);
$window.addEventListener("online", function () {
$rootScope.$apply(function() {
$rootScope.online = true;
// $window.location.reload();
});
}, false);
});
And add network information plugin in cordova

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.

Set timeout to layoutTemplate meteor / iron

I've been struggling to set 3 seconds timeout for my loadingTemplate.
Using the code bellow loadingTemplate is rendered but it does redirect to layoutTemplate after passing 3 seconds, as I expect.
Please find bellow my code and comments issues.
I also deployed this version to http://ns1-timeout.meteor.com/
I appreciate any help.
Router.configure({
layoutTemplate: 'applayout',
loadingTemplate: 'loading',
waitOn: function () {
var isTimePassed = false;
var clock = 3;
var timeLeft = function() {
if (clock > 0) {
clock--;
Session.set("time", clock);
console.log(clock);
} else {
console.log("That's All Folks");
//return true
isTimePassed = true;
Meteor.clearInterval(interval);
console.log('is Time passed: '+ isTimePassed);
return isTimePassed; // seems it is being ignored
}
};
var interval = Meteor.setInterval(timeLeft, 1000);
return {
ready: function () {
console.log('return ready: ' + isTimePassed);
return isTimePassed; // keeps the loading page and does not redirect to applayout if changed to false, loadingTemplate is not loaded and
}
}
}
});
Returning from a setInterval won't do anything. You need to use a reactive variable and have ready return the value of that reactive variable:
Router.configure({
layoutTemplate: 'applayout',
loadingTemplate: 'loading',
waitOn: function () {
Session.set('isTimePassed', false);
var isTimePassed = false;
var clock = 3;
var timeLeft = function() {
if (clock > 0) {
clock--;
Session.set("time", clock);
console.log(clock);
} else {
console.log("That's All Folks");
//return true
isTimePassed = true;
Meteor.clearInterval(interval);
console.log('is Time passed: '+ isTimePassed);
Session.set('isTimePassed', true);
}
};
var interval = Meteor.setInterval(timeLeft, 1000);
return {
ready: function () {
return Session.get('isTimePassed');
}
}
}
});
However, it is not exactly clear in your question if this is what you are intending to do.
After a few hours working on this I figured out that the best way to set a custom timeout for a loading template was not using Router.configure. The correct way would be setting a call to onBeforeAction function to my / route. So the code has ended as the following:
Router.configure({
layoutTemplate: 'appLayout',
loadingTemplate: 'loading'
});
Router.onBeforeAction(function(){
if(!Session.get('templateLoaded'))
{
setTimeOut(1000);
this.layout('loading');
this.render('loading');
}
else
{
this.render('home');
this.next();
}
},
{
only: ['home']
});
var setTimeOut = function (timeout) {
var self = this;
self._ready = false
self._dep = new Tracker.Dependency();
Meteor.setTimeout(function () {
self._ready = true;
self._dep.changed();
if(Meteor.isClient){
Session.set('templateLoaded', true); // set session variable to true so applayout Template will be rendered
}
}, timeout);
return function () {
self._dep.depend();
return function () {
return self._ready;
}
}
};

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.

Categories

Resources