Hi I have a situation here,
I have created a dual input directive. Can you please help to in the below scenario.
When I change the model value via controller to undefined, the view values are not cleared. Here is the Codes,
My Dual Input Directive is as follows,
angular.module("awcQuoteBuy.directives")
.directive('dualInput', function($timeout, inputValidationService) {
return {
restrict: 'E',
templateUrl: 'app/partials/common/doubleInput.html',
scope: {
modelValue: '=',
size: '#',
fieldError: '#',
blurFn: '&loseFocus'
},
link: function postLink(scope, element, attrs, ctrl) {
scope.leftFocused = false;
scope.rightFocused = false;
scope.$watch('left', function(newVal, oldVal) {
if (newVal!==oldVal) {
var tmp = (newVal) ? inputValidationService.formatNumber(newVal+'') : '';
scope.modelValue = tmp + '|'+ scope.getOtherValue(scope.right);
}
});
scope.$watch('right', function(newVal, oldVal) {
if (newVal!==oldVal) {
var tmp = (newVal) ? inputValidationService.formatNumber(newVal+'') : '';
scope.modelValue = scope.getOtherValue(scope.left) + '|' + tmp;
}
});
scope.getOtherValue = function(value) {
return (value && value!=='') ? inputValidationService.formatNumber(value+'') : '';
};
//will set the value initially
$timeout(function() {
if (!scope.modelValue || scope.modelValue===null) {
scope.modelValue = '';
}
if (scope.modelValue!=='') {
var splitIndex = scope.modelValue.indexOf('|');
if (splitIndex>=0) {
var values = scope.modelValue.split('|');
scope.left = values[0];
scope.right = values[1];
} else {
scope.left = scope.modelValue;
}
}
});
/*
Below functions will add on-blur (lose focus) support to both fields.
*/
scope.focusLeft = function() {
scope.leftFocused = true;
};
scope.blurLeft = function() {
scope.leftFocused = false;
$timeout(function() {
if (!scope.rightFocused) {
scope.blurFn();
}
}, 100);
};
scope.focusRight = function() {
scope.rightFocused = true;
};
scope.blurRight = function() {
scope.rightFocused = false;
$timeout(function() {
if (!scope.leftFocused) {
scope.blurFn();
}
}, 100);
};
}
};
});
The HTML Piece of code is as follows,
<dual-input model-value="dualInput[$index]" ng-switch-when="DUAL_NUMBER" size="{{q.length}}"
field-error="{{q.invalid || (nextClicked && !validateGeneralQuestion(acc.memberId, q))}}" id="{{'gQDual'+$index}}"
lose-focus="saveGeneralAnswer(acc.memberId, q)"></dual-input>
In My Controller when I set the scope value to undefined or null, the entered values in the view is not cleared. Please help me here what I should do to clear this value
$scope.dualInput[$index]=undefined;
The directive itself has got the auto initialize feature. So I had to re render the directive whenever I wanted to reinitialize.
If you want to explicitly update user ctrl.$setViewvalue = ""
I am using CK-Editor 4. In which I have created Directive. When I click on Textarea my cursor pointer is Move to First position. I want my cursor position should be available when I click in any of the Place inside Textarea. It should not be able to move first or last position until I click on last position.
vpb.directive('ckeInline', function ($timeout, $parse, $rootScope,$) {
return {
require: "ngModel",
link: function (scope, element, attrs, ngModel) {
if (attrs.ckeInlineShowtitle) ngModel = "";
isMobile = $(".ipad, .ipod, .android").length > 0;
var destroy_this_editor = function(id)
{
setTimeout(function () {
try{
CKEDITOR.instances[id].destroy(true);
} catch (ex) {
}
},500)
}
if (!isMobile) {
var create_and_focus = function () {
if (scope.setup.edit_mode || attrs.ckeNonEditMode) {
attrs.$set('contenteditable', true);
var a_id = attrs.ckeInlineId;
var menu_selector = attrs.ckeInlineMenu;
//get editor
//create editor if doesn't exist
var e = CKEDITOR.instances[a_id];
if (!e) {
element.menu = $(menu_selector);
//set up behavior for menu
uif.wire_up_menu(element, scope);
//hide all menu bars
$("nav.text-editor-menu-bar").hide();
//create editor
var config = {
toolbar: "More",
on: {
'blur': function () {
save_editor_content(function () {
destroy_this_editor(a_id);
});
},
'focusout': function () {
save_editor_content(function () {
destroy_this_editor(a_id);
});
},
'focus': function () {
//show the current menu
element.menu.show();
//fix menu width
uif.stretch_menu(element);
},
'instanceReady': function (event,element) {
//----------------I think,Here i want logic to set caret sign or set mouse
//pointer to appropriate place
// event.editor.focus();
// element.focus();
}
}
};
if (attrs.ckeInlineToolbar) {
config.toolbar = attrs.ckeInlineToolbar;
}
var editor = CKEDITOR.inline(a_id, config);
if (attrs.ckeInlineOnInit) {
uif.apply_scope($rootScope, $parse(attrs.ckeInlineOnInit));
}
}
else
{
e.focus();
element.focus();
}
} else
{
attrs.$set('contenteditable', false);
}
}
element.click(function () {
create_and_focus();
});
if (attrs.ckeInlineFocusWatch) {
scope.$watch(function () {
return $parse(attrs.ckeInlineFocusWatch);
}, function () {
if (attrs.ckeInlineFocusCondition == undefined || $parse(attrs.ckeInlineFocusCondition)() == true) {
create_and_focus();
}
})
}
var saving = false;
var save_editor_content = function (cb) {
if (!saving)
{
saving = true;
var a_id = attrs.ckeInlineId;
if (a_id) {
var editor = CKEDITOR.instances[a_id];
if (editor) {
var menu_selector = attrs.ckeInlineMenu;
element.menu.hide();
//attrs.$set('contenteditable', false);
var newValue = editor.getData().replace(/ /, ' ');
if (ngModel.$modelValue != newValue) {
if (attrs.ckeInlineBlurBool) {
$parse(attrs.ckeInlineBlurBool).assign($rootScope, false);
}
ngModel.$setViewValue(newValue);
if (attrs.ckeInlineSave) {
uif.apply_scope(scope, $parse(attrs.ckeInlineSave));
}
$timeout(function () {
saving = false;
if (cb) cb();
}, 1100)
} else
{
saving = false;
$rootScope.setup.blcok_edits = false;
$rootScope.setup.block_all_editors = false;
if (cb) cb();
}
}
}
else
{
saving = false;
}
}
};
} else if (attrs.ckeNonEditMode) {
attrs.$set('contenteditable', true);
element.blur(function () {
ngModel.$setViewValue(element.html().replace(/ /, ' '));
if (attrs.ckeInlineSave) {
uif.apply_scope(scope, $parse(attrs.ckeInlineSave));
}
})
}
}
}
});
I need a jasmine code changes, but I have to complete set of jasmine for the anonymous function. I am new to this. I tried but, I'm not able to achieve fully. Please help me.
Html file
<div ng-class="{ 'mainPassdownFont mainPassdownNoteLayout noteEditBackground': isBeingEdited(note), 'mainPassdownFont mainPassdownNoteLayout': isNotBeingEdited(note) }" >
<textarea ng-attr-id="{{ 'note-' + note.PassdownNoteID }}" ng-show="isBeingEdited(note)" class="mainPassdownFont passdownTextAreaLayout">{{ note.NoteText }}</textarea>
<div ng-hide="isBeingEdited(note)" class="mainPassdownFont passdownTextAreaLayout">
<pre class="notePre">{{ note.NoteText }}</pre>
</div>
<input class="passdownNoteInlineCheckbox" ng-attr-id="{{ 'checkbox-' + note.PassdownNoteID }}" ng-model="cbModel" ng-change="checkBoxChanged(note)" ng-checked="isClaimed(note)" type="checkbox" name="notesCheckbox" value="notesCheckbox">
<div ng-show="isClaimed(note)" class="downArrowIcon passdownNoteDownArrowLayout" ></div>
<div ng-show="isClaimed(note)" class="passdownAnnotationFont claimTextContainerLayout" >
<p class="claimNameLayout">{{ note.Created.By.Text }}</p>
<p class="claimDateLayout">{{ note.Created.Date.Local | date : 'MMM d, y h:mm a' }}</p>
</div>
<div ng-hide="isClaimed(note)" ng-click="claimNote(note)" class="passdownAnnotationFont claimClickTextContainerLayout" >
<p class="claimNameLayout">Click to Claim</p>
</div>
<div class="passdownAnnotationFont authorTextContainerLayout" >
<p class="claimNameLayout">{{ note.LastModified.By.Text }}</p>
<p class="claimDateLayout">{{ note.LastModified.Date.Local | date : 'MMM d, y h:mm a' }}</p>
</div>
<div class="actionIconContainerLayout" >
<div class="deleteIcon inlineActionIconLayout" ng-click="deleteNote(note)"></div>
<div class="editIcon inlineActionIconLayout" ng-click="editNote(note)"></div>
<div class="addIcon inlineActionIconLayout" ng-click="addSubNote(note)"></div>
</div>
<div class="btnforpassdownTextAreaLayout">
<button ng-attr-id="{{ 'btn-' + note.PassdownNoteID }}" type="button" class="btn btnpassdownTextAreaLayout" ng-show="isBeingEdited(note)" ng-click="completeEdit(note)">Save</button>
<button ng-attr-id="{{ 'btn-' + note.PassdownNoteID }}" type="button" class="btn btnpassdownTextAreaLayout" ng-show="isBeingEdited(note)" ng-click="cancelEdit(note)">Cancel</button>
</div>
</div> </div>
</div>
</div>
js changes
app.controller('passdownCtrl',
['$rootScope', '$scope', '$http', '$resource', '$location', 'PassdownNotesData','$window', 'userService',
function($rootScope, $scope, $http, $resource, $location, PassdownNotesData, $window, userService) { $scope.passdownNotesData={ "reviewedDateUtc" : "01-01-2000T15:00", "results": [] };
$scope.reviewDate = null;
$scope.indexBeingEdited = -1;
$scope.inputfocus = false;
$scope.filterText = "";
// Go get trips from the server via an http Get Call. If successful, assign the response to
// $scope.tripData. If errors occur, assign them to the tripData for the UI to look for
// and provide the user some possible action.
$scope.passdownNotesData = PassdownNotesData.getData();
if ($scope.passdownNotesData.results.length == 0) {
PassdownNotesData.updatePassdownNotesData()
.then(function(result) {
$scope.passdownNotesData = result;
$scope.reviewDate = parseBoldIQDate(result.reviewedDateUtc); //error
}, function(error) {
alert('Error getting Passdown Notes data in controller');
});
} else {
//$scope.selectedRequestIndex = 0;
//$scope.selectedRequest = $scope.controllerRequestList.requestList[0];
}
parseBoldIQDate = function(dateStr) {
var newDate = new Date();
newDate.setUTCMonth(Number(dateStr.substr(0,2)) - 1);
newDate.setUTCDate(Number(dateStr.substr(3,2)));
newDate.setUTCFullYear(Number(dateStr.substr(6,4)));
newDate.setUTCHours(Number(dateStr.substr(11,2)));
newDate.setUTCMinutes(Number(dateStr.substr(14,2)));
return newDate;
};
$scope.noteState = function (cat, checkOpen) {
var containerName = cat + 'ContainerDiv';
var containerElement = document.getElementById(containerName);
if (containerElement != null) {
var isOpen = false;
if (containerElement.style.display == "block") {
isOpen = true;
}
return (isOpen == checkOpen);
}
return false;
};
getMaxNoteId = function() {
// create a new note structure, add it to the list, persist it, and put it in edit mode
var maxNoteId = 0;
for (var i = 0; i < $scope.passdownNotesData.results.length; i++ ) {
if ($scope.passdownNotesData.results[i].PassdownNoteID >= maxNoteId) {
maxNoteId = $scope.passdownNotesData.results[i].PassdownNoteID;
}
for (var j = 0; j < $scope.passdownNotesData.results[i].SubNotes.length; j++ ) {
if ($scope.passdownNotesData.results[i].SubNotes[j].PassdownNoteID >= maxNoteId) {
maxNoteId = $scope.passdownNotesData.results[i].SubNotes[j].PassdownNoteID;
}
}
}
return maxNoteId;
};
$scope.addNote = function(cat, event) {
// create a new note structure, add it to the list (local and global), persist it, and put it in edit mode
// create new note
var currentDate = new Date();
var newNote = new Object();
newNote.PassdownNoteID = getMaxNoteId() + 1;
newNote.Category = new Object();
newNote.Category.Text = cat;
newNote.NoteText = "Default Note Text";
newNote.Created = new Object();
// newNote.Created.ClaimStatus = "false";
newNote.Created.By = new Object();
newNote.Created.By.ID = 0;
newNote.Created.By.Text = "N/A";
newNote.Created.Date = new Object();
newNote.Created.Date.Utc = createBoldIQDate(currentDate);
newNote.Created.Date.Local = currentDate;
newNote.LastModified = new Object();
newNote.LastModified.By = new Object();
newNote.LastModified.By.ID = 17;
newNote.LastModified.By.Text = userService.getUser();
newNote.LastModified.Date = new Object();
newNote.LastModified.Date.Utc = createBoldIQDate(currentDate);
newNote.LastModified.Date.Local = currentDate;
newNote.SubNotes = new Array();
// Add it to local and global lists
//$scope.passdownNotesData.results[$scope.passdownNotesData.results.length] = newNote;
var dataCopy = PassdownNotesData.getData();
dataCopy.results[dataCopy.results.length] = newNote;
// Persist the updated data to the server
PassdownNotesData.writeUpdatesToServer(dataCopy);
// Put the display in Edit mode
$scope.indexBeingEdited = newNote.Id;
};
$scope.getNumUnclaimedForCategory = function(cat) {
var numUnclaimed = 0;
for (var i = 0; i < $scope.passdownNotesData.results.length; i++ ) {
if ($scope.passdownNotesData.results[i].Category.Text == cat) {
// If the main part of the note was updated, add 1 and call it good.
if ($scope.passdownNotesData.results[i].IsActive == "false") {
numUnclaimed++;
}
}
}
return numUnclaimed;
};
$scope.checkBoxChanged = function(note) {
var elementStr = "checkbox-" + note.PassdownNoteID;
var checkboxElement = document.getElementById(elementStr);
var val = checkboxElement.checked;
if (val == false) {
// Here we will unclaim the note
var dataCopy = PassdownNotesData.getDatacompleteSubNoteEdit();
// Update the real data 'and' our local scope copy, and write the real stuff back to the server
for (var i = 0; i < dataCopy.results.length; i++) {
if (note.PassdownNoteID == dataCopy.results[i].PassdownNoteID) {
console.log("inside here ", note.PassdownNoteID);
dataCopy.results[i].IsActive = "false";
//Update our local copy
$scope.passdownNotesData.results[i].IsActive = "false";
}
}
PassdownNotesData.writeUpdatesToServer(dataCopy); // $scope.passdownNotesData);
} else {
$scope.claimNote(note);
}
};
$scope.editSubNote = function(subNote) {
$scope.indexBeingEdited = subNote.PassdownNoteID;
var elementStr = "subNote-" + subNote.PassdownNoteID;
var textAreaElement = document.getElementById(elementStr);
$scope.subNotesText = textAreaElement.value;
};
$scope.isClaimed = function(note) {
if (note.isActive == "true") {
return true;
} else {
return false;
}
};
$scope.claimNote = function(note) {
var dataCopy = PassdownNotesData.getData();
// Update the real data 'and' our local scope copy, and write the real stuff back to the server
for (var i = 0; i < dataCopy.results.length; i++) {
if (note.PassdownNoteID == dataCopy.results[i].PassdownNoteID) {
dataCopy.results[i].isActive = "true";
dataCopy.results[i].Created.By.ID = 17;
dataCopy.results[i].Created.By.Text = $scope.loggedInUser;
var currentDate = new Date();
dataCopy.results[i].Created.Date.Utc = createBoldIQDate(currentDate);
dataCopy.results[i].Created.Date.Local = currentDate;
$scope.passdownNotesData.results[i].Created.Date.Utc = dataCopy.results[i].Created.Date.Utc;
$scope.passdownNotesData.results[i].Created.Date.Local = currentDate;
}
}
PassdownNotesData.writeUpdatesToServer(dataCopy); // $scope.passdownNotesData);
};
createBoldIQDate = function(date) {
var monthStr = (date.getUTCMonth() + 1).toString();
if (monthStr.length == 1) {
monthStr = "0" + monthStr;
}
var dateStr = (date.getUTCDate()).toString();
if (dateStr.length == 1) {
dateStr = "0" + dateStr;
}
var yearStr = (date.getUTCFullYear()).toString();
var hoursStr = (date.getUTCHours()).toString();
if (hoursStr.length == 1) {
hoursStr = "0" + hoursStr;
}
var minutesStr = (date.getUTCMinutes()).toString();
if (minutesStr.length == 1) {
minutesStr = "0" + minutesStr;
}
var dateStr = monthStr + "-" + dateStr + "-" + yearStr + "T" + hoursStr + ":" + minutesStr;
return dateStr;
};
$scope.filterTrips = function(note) {
if (note.Category.Text == 'Trips') { return true; } else { return false; }
};
$scope.filterWeather = function(note) {
if (note.Category.Text == 'Weather') { return true; } else { return false; }
};
$scope.filterMaintenance = function(note) {
if (note.Category.Text == 'Maintenance') { return true; } else { return false; }
};
$scope.filterGeneral = function(note) {
if (note.Category.Text == 'General') { return true; } else { return false; }
};
$scope.toggleNotesContainer = function(cat, event) {
var containerName = cat + 'ContainerDiv';
var containerElement = document.getElementById(containerName);
if (containerElement != null) {
if (containerElement.style.display == 'none') {
containerElement.style.display = 'block';
if (cat == "Trips") {
var buttonElement = document.getElementById("passdownToggleHideShowButton");
buttonElement.innerHTML = "Hide All";
}
} else {
containerElement.style.display = 'none';
if (cat == "Trips") {
var buttonElement = document.getElementById("passdownToggleHideShowButton");
buttonElement.innerHTML = "Show All";
}
}
}
};
$scope.toggleHideShowPassdown = function() {
// We will use the Trips container as the indicator of whether to "open All" or "Close all"
// TODO - when we get time, we want to animate the open/close of these containers
var tripsContainerElement = document.getElementById('TripsContainerDiv');
if (tripsContainerElement != null) {
if (tripsContainerElement.style.display == 'none') {
// This means we need to open all the containers, and change the text on the button to
// "hide all"
var buttonElement = document.getElementById("passdownToggleHideShowButton");
buttonElement.innerHTML = "Hide All";
var weatherContainerElement = document.getElementById('WeatherContainerDiv');
var maintenanceContainerElement = document.getElementById('MaintenanceContainerDiv');
var GeneralContainerElement = document.getElementById('GeneralContainerDiv');
tripsContainerElement.style.display = 'block';
weatherContainerElement.style.display = 'block';
maintenanceContainerElement.style.display = 'block';
GeneralContainerElement.style.display = 'block';
} else {
// This means we need to close all the containers, and change the text on the button to
// "show all"
var buttonElement = document.getElementById("passdownToggleHideShowButton");
buttonElement.innerHTML = "Show All";
var weatherContainerElement = document.getElementById('WeatherContainerDiv');
var maintenanceContainerElement = document.getElementById('MaintenanceContainerDiv');
var GeneralContainerElement = document.getElementById('GeneralContainerDiv');
tripsContainerElement.style.display = 'none';
weatherContainerElement.style.display = 'none';
maintenanceContainerElement.style.display = 'none';
GeneralContainerElement.style.display = 'none';
}
}
};
var containerElement = document.getElementById("TripsContainerDiv");
containerElement.style.display = 'block';
containerElement = document.getElementById("WeatherContainerDiv");
containerElement.style.display = 'block';
containerElement = document.getElementById("MaintenanceContainerDiv");
containerElement.style.display = 'block';
containerElement = document.getElementById("GeneralContainerDiv");
containerElement.style.display = 'block';
$scope.gotoPassdownScreen = function () {
//$location.path('#/requests/legDetails');
};
}]);
Jasmine js file..
describe('passdownnotes controller spec',function() {
var ctrlScope;
var rootScope;
var userServiceMock;
var PassdownNotesDataMock;
beforeEach(function() {
module('app'); // load jiops module
});
beforeEach(inject(function ($rootScope, $controller, $httpBackend, $q) {
ctrlScope = $rootScope.$new();
rootScope = $rootScope;
PassdownNotesDataMock = {
updatePassdownNotesData: function() {
var deferred = $q.defer();
deferred.resolve(mockPassdownNotesData);
return deferred.promise;
},
getData: function() {
return mockPassdownNotesData;
}
};
userServiceMock = {
getUser: function() {
var deferred = $q.defer();
deferred.resolve(mockUserData);
return deferred.promise;
}
};
$controller('passdownCtrl', {
$scope: ctrlScope,
PassdownNotesData:PassdownNotesDataMock,
userService:userServiceMock
});
}));
describe('passdownnotes controller',function() {
it('should have the correct initial configuration', function() {
expect(ctrlScope.indexBeingEdited).toEqual(-1);
expect(ctrlScope.inputfocus).toBe(false);
expect(ctrlScope.reviewDate).toBe(null);
expect(ctrlScope.passdownNotesData).toEqual(0);
expect(ctrlScope.filterText).toBe("");
});
});
});
var mockPassdownNotesData =
{
"results":[
{
"Created":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-02-2015T14:20:26",
"TzAbbrev":" MDT",
"Utc":"07-02-2015T20:20:26"
}
},
"IsActive":true,
"LastModified":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-02-2015T14:29:32",
"TzAbbrev":" MDT",
"Utc":"07-02-2015T20:29:32"
}
},
"NoteText":"test note3333",
"PassdownNoteID":1,
"AssignedTo":{
"ID":0,
"Text":""
},
"Category":{
"ID":692,
"Text":"Trips"
},
"DateAssigned":null,
"DueDate":{
"Local":"07-19-2015T18:00",
"TzAbbrev":" MDT",
"Utc":"07-20-2015T00:00"
},
"ExpirationDate":null,
"SubNotes":[
{
"Created":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-02-2015T14:20:27",
"TzAbbrev":" MDT",
"Utc":"07-02-2015T20:20:27"
}
},
"IsActive":true,
"LastModified":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-02-2015T14:20:27",
"TzAbbrev":" MDT",
"Utc":"07-02-2015T20:20:27"
}
},
"NoteText":"sample sub note",
"PassdownNoteID":2
}
]
},
{
"Created":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-07-2015T11:12:03",
"TzAbbrev":" MDT",
"Utc":"07-07-2015T17:12:03"
}
},
"IsActive":true,
"LastModified":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-07-2015T11:12:03",
"TzAbbrev":" MDT",
"Utc":"07-07-2015T17:12:03"
}
},
"NoteText":"Test Passdown Note",
"PassdownNoteID":3,
"AssignedTo":{
"ID":302,
"Text":"Button, Jenson"
},
"Category":{
"ID":695,
"Text":"General"
},
"DateAssigned":{
"Local":"07-07-2015T11:12",
"TzAbbrev":" MDT",
"Utc":"07-07-2015T17:12"
},
"DueDate":null,
"ExpirationDate":null,
"SubNotes":[
{
"Created":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-07-2015T11:12:03",
"TzAbbrev":" MDT",
"Utc":"07-07-2015T17:12:03"
}
},
"IsActive":true,
"LastModified":{
"By":{
"ID":3,
"Text":"Developer, Jeppesen"
},
"Date":{
"Local":"07-07-2015T11:12:03",
"TzAbbrev":" MDT",
"Utc":"07-07-2015T17:12:03"
}
},
"NoteText":"Test of passdown subnote",
"PassdownNoteID":4
}
]
}
]
};
describe('Controller: passdownCtrl', function() {
var $rootScope,
$scope,
$controller,
$http,
$resource,
PassdownNotesData,
$window,
userService,
ctrl;
// Mock required modules
angular.mock.module('PassdownNotesDataModule');
beforeEach(function(){
angular.mock.module(function($provide){
PassdownNotesData = jasmine.createSpyObj('PassdownNotesData', ['getData']);
// Optionally if you want service return some data
// PassdownNotesData.getData.and.returnValue({
// anyProperty: anyValue
// });
$provide.value('PassdownNotesData', PassdownNotesData);
});
});
beforeEach(function(){
angular.mock.module(function($provide){
userService = jasmine.createSpyObj('userService', ['getUser']);
// Optionally if you want service return some data
// userService.getUser.and.returnValue({
// anyProperty: anyValue
// });
$provide.value('userService', userService);
});
});
beforeEach(angular.mock.inject(function(_$rootScope_, _$controller_, _$http_, _$resource_, _PassdownNotesData_, _$window_, _userService_){
$rootScope = _$rootScope_;
$scope = _$rootScope_.$new();
$controller = _$controller_;
$http = _$http_;
$resource = _$resource_;
PassdownNotesData = _PassdownNotesData_;
$window = _$window_;
userService = _userService_;
ctrl = $controller('passdownCtrl as ctrl', {
$rootScope: $rootScope,
$scope: $scope,
$http: $http,
$resource: $resource,
PassdownNotesData: PassdownNotesData,
$window: $window,
userService: userService
});
}));
describe('on controller initialization', function(){
it('should set reviewDate', function(){
expect($scope.reviewDate).toBe(null);
});
it('should set indexBeingEdited', function(){
expect($scope.indexBeingEdited).toBe(-1);
});
it('should set inputfocus', function(){
expect($scope.inputfocus).toBe(false);
});
it('should set filterText ', function(){
expect($scope.filterText).toBe('');
});
});
describe('Function: passdownNotesData', function(){
it('should get data', function(){
$scope.passdownNotesData();
expect(PassdownNotesData.getData).toHaveBeenCalled();
})
});
...
});
Put any function and properties to the viewmodel of controller, not in the scope:
function SomeController(){
var vm = this;
vm.someProperty = ...;
vm.someFunction = someFunction;
function someFunction(){
....
}
}
app.controller('passdownCtrl', function($scope, PassdownNotesData) {
var vm = this;
vm.passdownNotesData = PassdownNotesData.getData();
if (vm.passdownNotesData.results.length == 0) {
PassdownNotesData.updatePassdownNotesData()
.then(function(result) {
vm.passdownNotesData = result;
vm.reviewDate = parseBoldIQDate(result.reviewedDateUtc);
}, function(error) {
alert('Error getting Passdown Notes data in controller');
});
}
var parseBoldIQDate = function(dateStr) {
var newDate = new Date();
newDate.setUTCMonth(Number(dateStr.substr(0, 2)) - 1);
newDate.setUTCDate(Number(dateStr.substr(3, 2)));
newDate.setUTCFullYear(Number(dateStr.substr(6, 4)));
newDate.setUTCHours(Number(dateStr.substr(11, 2)));
newDate.setUTCMinutes(Number(dateStr.substr(14, 2)));
return newDate;
};
});
describe('Controller: passdownCtrl', function(){
var $scope,
$controller,
$q,
deferred,
PassdownNotesData,
ctrl,
window;
beforeEach(angular.mock.module('requiredModule'));
beforeEach(function(){
angular.mock.module(function($provide){
PassdownNotesData = jasmine.createSpyObj('PassdownNotesData', ['getData', 'updatePassdownNotesData']);
$provide.value('PassdownNotesData', PassdownNotesData);
});
});
beforeEach(function(){
angular.mock.module(function($provide){
window = jasmine.createSpyObj('window', ['alert']);
$provide.value('window', window);
});
});
beforeEach(inject(function(_$rootScope_, _$controller_, _$q_, _PassdownNotesData_){
$scope = _$rootScope_.$new();
$controller = _$controller_;
$q = _$q_;
PassdownNotesData = _PassdownNotesData_;
deferred = $q.defer();
ctrl = $controller('passdownCtrl as ctrl', {
$scope: $scope,
PassdownNotesData: PassdownNotesData
});
}));
it('should resolve promise', function(){
var data = {
results: ['0']
}
var result = {
name: '0',
reviewedDateUtc: '12'
};
PassdownNotesData.getData.and.returnValue(data);
PassdownNotesData.updatePassdownNotesData.and.returnValue(deferred.promise);
deferred.resolve(result);
$scope.$digest();
expect(ctrl.passdownNotesData).toBe(result);
// function parseBoldIQDate must be executed with
// result.reviewedDateUtc value
expect(ctrl.reviewDate).toEqual('Thu Nov 30 0 02:00:50 GMT+0200 (FLE Standard Time)');
});
it('should reject promise', function(){
var data = {
results: ['0']
}
PassdownNotesData.getData.and.returnValue(data);
PassdownNotesData.updatePassdownNotesData.and.returnValue(deferred.promise);
deferred.reject({});
$scope.$digest();
expect(window.alert).toHaveBeenCalledWith('Error getting Passdown Notes data in controller');
});
});
I am using Angular-chosen and I am unable to set dynamic options.
<div ng-init="delegate.getCategories()">
<select chosen="" multiple="multiple"
ng-model="tags" ng-change="delegate.getCategories()"
ng-options="s.categoryName for s.categoryName in tagsList">
</select>
</div>
My controller class
getCategories: function(){
constantsService.getCategories($scope.category, this.onGetCategories, this.onFailure);
alert($scope.category);
},
onGetCategories:function(response){
$scope.tagsList = response.categories;
alert(response);
},
onFailure:function(response){
alert(response);
}
on page load the init gets the categories form the backend and and sets in tagsList variable but its not there when the html loads.
my directive angular-chosen is working nice, see the codes:
HTML:
<select id="selectWithChosen"
name="selectWithChosen"
data-ng-model="theSelectedChosenValue"
data-ng-options="tp as tp.alias for tp in myList"
sgc-chosen
data-width="('100%')">
<option value="">Select One Element</option>
</select>
JavaScript which load the content of myList
$http.get("/settings/myList").success(function(data) {
$scope.myList = data;
});
I can acess the value that user selected with the next code:
//the value of my select with chosen is here, in JS:
//**remember** the variable "theSelectedChosenValue" is only fill after you select the value on chosen component.
$scope.theSelectedChosenValue;
Finally, the implementation of my angular-chosen directive:
"use strict";
// baseado em https://github.com/localytics/angular-chosen
components.directive('sgcChosen', function($timeout) {
var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
var CHOSEN_OPTION_WHITELIST, NG_OPTIONS_REGEXP, isEmpty, snakeCase;
NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/;
CHOSEN_OPTION_WHITELIST = ['noResultsText', 'allowSingleDeselect', 'disableSearchThreshold', 'disableSearch', 'enableSplitWordSearch', 'inheritSelectClasses', 'maxSelectedOptions',
'placeholderTextMultiple', 'placeholderTextSingle', 'searchContains', 'singleBackstrokeDelete', 'displayDisabledOptions', 'displaySelectedOptions', 'width'];
snakeCase = function(input) {
return input.replace(/[A-Z]/g, function($1) {
return "_" + ($1.toLowerCase());
});
};
isEmpty = function(value) {
var key;
if (angular.isArray(value)) {
return value.length === 0;
} else if (angular.isObject(value)) {
for (key in value) {
if (value.hasOwnProperty(key)) {
return false;
}
}
}
return true;
};
return {
restrict: 'A',
require: '?ngModel',
terminal: true,
link: function(scope, element, attr, ngModel) {
var chosen, defaultText, disableWithMessage, empty, initOrUpdate, match, options, origRender, removeEmptyMessage, startLoading, stopLoading, valuesExpr, viewWatch;
attr.noResultsText = attr.noResultsText ? attr.noResultsText : "'Sem resultados para: '";
element.children('chosen-search').children().attr('maxlength', 100);
element.addClass('localytics-chosen');
options = scope.$eval(attr.chosen) || {};
angular.forEach(attr, function(value, key) {
if (__indexOf.call(CHOSEN_OPTION_WHITELIST, key) >= 0) {
return options[snakeCase(key)] = scope.$eval(value);
}
});
startLoading = function() {
return element.addClass('loading').trigger('chosen:updated');
};
stopLoading = function() {
scope.$evalAsync(function() {
return element.removeClass('loading').trigger('chosen:updated');
});
};
chosen = null;
defaultText = null;
empty = false;
initOrUpdate = function() {
if (chosen) {
scope.$evalAsync(function() {
return element.trigger('chosen:updated');
});
} else {
chosen = element.chosen(options).data('chosen');
chosen.search_field[0].setAttribute('maxlength', 100);
return defaultText = chosen.default_text;
}
};
removeEmptyMessage = function() {
empty = false;
return element.attr('data-placeholder', defaultText);
};
disableWithMessage = function() {
empty = true;
scope.$evalAsync(function() {
return element.attr('data-placeholder', '').attr('disabled', true).trigger('chosen:updated');
});
};
if (ngModel) {
origRender = ngModel.$render;
ngModel.$render = function() {
origRender();
return initOrUpdate();
};
viewWatch = function() {
return ngModel.$viewValue;
};
scope.$watch(viewWatch, ngModel.$render, true);
} else {
initOrUpdate();
}
attr.$observe('disabled', function(isDisabled) {
scope.$evalAsync(function() {
element.prop('disabled', isDisabled);
element.trigger('chosen:updated');
});
return true;
});
if (attr.ngOptions && ngModel) {
match = attr.ngOptions.match(NG_OPTIONS_REGEXP);
valuesExpr = match[7];
return scope.$watchCollection(valuesExpr, function(newVal, oldVal) {
if (angular.isUndefined(newVal)) {
return startLoading();
} else {
if (empty) {
removeEmptyMessage();
}
stopLoading();
if (isEmpty(newVal)) {
return disableWithMessage();
} else {
element.attr('data-placeholder', '').attr('disabled', false).trigger('chosen:updated');
}
}
});
}
}
};
});
This angular-chosen code is available HERE.
I need to pass two arguments from directive to a function which is defined in controller.
HTML
<div paginate="allResults" change-page="changePage()"></div>
Directive
app.directive('paginate', function () {
return {
scope: {
allResults: '=paginate',
changePage:'&'
},
template: '<ul class="pagination" ng-show="totalPages > 1">' +
' <li><a ng-click="firstPage()">«</a></li>' +
' <li><a ng-click="prevPage()">‹</a></li>' +
' <li ng-repeat="n in pages">' +
' <a class="current-{{n==current_page}}" ng-bind="n" ng-click="setPage(n)">1</a>' +
' </li>' +
' <li><a ng-click="nextPage()">›</a></li>' +
' <li><a ng-click="last_page()">»</a></li>' +
'</ul>',
link: function (scope) {
scope.nextPage = function () {
if (scope.current_page < scope.totalPages) {
scope.current_page++;
}
};
scope.prevPage = function () {
if (scope.current_page > 1) {
scope.current_page--;
}
};
scope.firstPage = function () {
scope.current_page = 1;
};
scope.last_page = function () {
scope.current_page = scope.totalPages;
};
scope.setPage = function (page) {
scope.current_page = page;
};
var paginate = function (results, oldResults) {
if (oldResults === results) return;
scope.current_page = results.current_page;
scope.total = results.total;
scope.totalPages = results.last_page;
scope.pages = [];
for (var i = 1; i <= scope.totalPages; i++) {
scope.pages.push(i);
}
};
var pageChange = function (newPage, last_page) {
scope.changePage(newPage, last_page);
};
scope.$watch('allResults', paginate);
scope.$watch('current_page', pageChange);
}
}
});
Controller
function CareerCtrl($scope, $http, Career) {
$scope.init = function () {
Career.get({}, function (response) {
$scope.careers = response.careers.data;
$scope.allResults = response.careers;
}, function (error) {
console.log(error);
$scope.careers = [];
});
}; // init
$scope.changePage = function(newPage, last_page) {
console.log(newPage);
console.log(last_page);
if (newPage == last_page) return;
Career.get({
page: newPage
}, function (response) {
angular.copy(response.careers.data,scope.allResults.data);
scope.allResults.current_page = response.careers.current_page;
}, function (error) {
console.log(error);
$scope.allResults.data = [];
});
}
} // Ctrl
Now I am getting undefined for newPage and last_page in controller.
See my fiddle here
Solution one (fiddle):
Html:
<div paginate="allResults" change-page="changePage(newPage, last_page)"></div>
Directive:
var pageChange = function (newPage, last_page) {
scope.changePage({
newPage: newPage,
last_page: last_page
});
};
Solution two (fiddle):
Html:
<div paginate="allResults" change-page="changePage"></div>
Directive:
var pageChange = function (newPage, last_page) {
var expressionHandler = scope.changePage();
expressionHandler(newPage, last_page);
};
Note that you need to change scope to $scope in two places in your controller function $scope.changePage in your original fiddle.