I am trying to execute a fuction when a change occurs in one tab, the change should reflect in other tab too.
i write this and it is working fine in the same tab i change even i check manually browser localstorage and see it works nice.
but the problem, the change not reflect in other tab too.
I mean, i opened two tab and when i change something in one tab, in other tab it should reflect.
Whenever any change occurs in one tab, 2nd tab should execute this $scope.getAllContact(); and wait for another change, if another change occurs, $scope.getAllContact(); should be executed.
$localStorage.editedData = response.data;
$scope.editedID = $localStorage.editedData.id;
if (response.data.id == $localStorage.editedData.id) {
$localStorage.isChanged = true;
}
while ($localStorage.isChanged == true) {
$scope.getAllContact();
break
}
I write above code;
Ignore below this code if you undertand above few line, below code is fuction, when change occurs, the fuction should be executed:
$scope.getAllContact = function() {
var data = $http.get("http://127.0.0.1:8000/api/v1/contact")
.then(function(response) {
$scope.contacts = response.data;
// below two line of codes will reload in every 10 millisecond if a request succcess
// in result, you will see refleation in other browser if any change occurs in another browser
// do nothing for now
}, function(response) {
//$scope.connectionError = "Opps ! Having Trouble in loading this page ! \n It's Connection Error !!!";
// below two line as as above two commented line
// do nothing for nw
});
};
$scope.getAllContact();
You need to check your local storage at a certain time difference
setInterval(function(){
if ($localStorage.isChanged == true) {
$scope.getAllContact();
}
}
}, 500);
See below code may helpfull
$scope.$apply(function() {
$scope.contacts = response.data;
});
or
As per my assumption at a time you can see only one tab. So,call $scope.getAllContact()
whenever your clicking on second tab.
Related
I have an anuglarJS controller that calls an API via a service to return data. Ths issue is that sometimes, the data is not being updated in a directive that uses the data that is returned.
However, digging into this resulted in observing some very strange behavior. I added several console logs to debug what was happening, and discovered that the number of items in a property on the array is changing from one console call to the next.
The controller code is as follows:
init(){
this.ftService.getSitePromise(true).then((result: ng.IHttpPromiseCallbackArg<Site>) => {
let ctrl = this;
ctrl.isLoadingItems = true;
ctrl.hideSplash = true;
ctrl.siteReady = true;
ctrl.curSite = result.data;
ctrl.curSite.Items = [];
console.log("end of header site call");
ctrl.$timeout(function () {
console.log(ctrl.curSite.Items);
console.log("start get site items first call")
ctrl.ftService.getSitePromise(false).then((result: ng.IHttpPromiseCallbackArg<Site>) => {
console.log("return first call result.data.Items: " + result.data.Items.length);
ctrl.curSite.Items = result.data.Items;
ctrl.isLoadingItems = false;
console.log("return first call ctrl.curSite.Items: " + ctrl.curSite.Items.length);
console.log(ctrl);
console.log(ctrl.curSite);
console.log(ctrl.curSite.Items);
});
}, 200);
});
}
The console from this code executing, when the data isn't being shown as expected is as follows:
Any insight as to how this is occurring, and/or how I might correct it, would be greatly appreciated.
Edit: I didn't read the comments before posting. I didn't see your problem was solved. Hopefully this may help someone else in the future??
Why/how do the elements of this array change between the console.log calls?
Objects can change in console.log calls because the deeper nested properties are accessed lazily meaning that the console will only grab them when you click the little arrow to expand the object or if they are a shallow property.
You can change this behavior by cloning the object using Object.assign though you may need to clone the object deeply (which Object.assign({}, myObj) does not.
The stackoverflow snippet console won't show the correct results. Open your chrome dev tools to see the real result.
// OPEN THE DEVELOPER TOOLS CONSOLE
let myObj = {
shallowProp: 'some value',
arr: ['initial value']
};
// notice that when this logs, it seems like the change to myObj happens before the log but it does not
console.log(
'myObj initial log',
myObj
);
// using `Object.assign` clones the object so that when expanded in the console, the value is the initial value
console.log(
'myObj initial log with Object.assign',
Object.assign({}, myObj)
);
// when the value is actually changed
myObj.arr = ['new value'];
// the final state
console.log('myObj after change', myObj);
Conclusion: try cloning your object before logging it the console.
I understand that Ext.Msg.Confirm is asynchronous, and will proceed if you do not provide a callback.
Below is my code - this is called if the user tries to navigate from the current screen while in edit mode. I'm passing in a callback to the method - fn is my callback event, but regardless of how I code this the logic continues to navigate away from the page. Is there anyway to stop propagation until the user has selected yes or no in the confirmation box?
Here is the code for the Confirmation:
displaySaveConfirmation: function(fn) {
var title = 'Do you want to Save?'
var msg = 'You are currently Editing Standard Text. Would you like to save your changes?'
var box = Ext.Msg.confirm(title, msg, function(buttonId, value) {
if (buttonId === 'no'){
fn.call();
} else {
return false;
}
}, this );
box.setZIndex(400);
box.setCls('alert-box');
var buttons = Ext.ComponentQuery.query('button', box);
for (var i=0; i<buttons.length; i++) {
if (buttons[i].getItemId()=="no")
buttons[i].addCls('blackBtn');
else if (buttons[i].getItemId()=="yes")
buttons[i].addCls('blueBtn');
this.addReleaseEvent(box, buttons[i]);
}
},
As of now you do the following:
The event is fired
You open the MessageBox
Your function returns, and it does not return "false".
The browser navigates away before the user can click "yes" or "no".
What you want to do is the following:
The event is fired
You open the MessageBox
Your function returns false.
The browser does not navigate away.
The user clicks "yes" or "no".
If the answer is "yes", you navigate to the previously requested target page manually (e.g. close the browser window, use history.back() or similar).
Alternatively, if the work to get that up and running (and tested, with all the possible cases how to navigate away and how to find the target) is too much, you can opt for the window.alert dialog instead, which does not look nearly as nice, but works synchronously.
Or you can do as I did: I just returned false after bringing up a MessageBox that says: "You cannot leave the page during edit. Please save or abort the post."
I am testing a SPA built with angular.js and im using Page Objects pattern to write my tests. In the app we have a number of lists that will be updated. For example there is a list of attachments that will update when ever attachments are added/removed. To add an attachment we have a modal window and when we upload a file and click ok. The file uploads and the lists update.
I have written 2 page objects, one for the upload modal window and the other one for the preview of the attachment list. In my tests i first get the current count of the attachments then i click on a button to activate the modal window and attach the file. Then i take another count of the attachments in the preview page and compare it to be incremented by 1. But the tests fails. The page object is not updated and it still shows attachment count as 2.
Test
it('Should attach a file when a file is selected and OK button is pressed.', function () {
var currentFileCount = viewMeetingTabPage.getMeetingAttachmentCount();
viewMeetingPage.clickAddAttachmentButton();
addAttchmentPage.attachFile();
addAttchmentPage.clickConfimAttachFileButton();
currentFileCount.then(function (curCount) {
viewMeetingTabPage.getMeetingAttachmentCount().then(function (newCount) {
expect(newCount).toBe(curCount + 1);
//expect(viewMeetingTabPage.getMeetingAttachmentName()).toBe('test-file.pdf');
});
});
});
ViewMeetingTabPage
this.getMeetingAttchments = function () {
return element.all(by.repeater('attachment in meeting.AttachmentViewModelList track by $index'));
};
this.getMeetingAttachmentCount = function () {
return this.getMeetingAttchments().count();
};
What i need to have is to somehow update the page object after i upload the file. How can i do that.
This is how the control-flow works. Executing the code for the test queues a bunch of promises. They get resolved in the order they were added to the flow while each of them waits for the previous to finish.
it('Should attach a file when a file is selected and OK button is pressed.', function () {
# Queues the count promise
var currentFileCount = viewMeetingTabPage.getMeetingAttachmentCount();
# Queues some other promises that would start
# to get executed once the one above finishes
viewMeetingPage.clickAddAttachmentButton();
addAttchmentPage.attachFile();
addAttchmentPage.clickConfimAttachFileButton();
# This piece of code branches-off the control-flow
# and gets executed immediately after currentFileCount is resolved
# i.e. before the clickAddAttachmentButton
currentFileCount.then(function (curCount) {
# That's why newCount equals curCount,
# they are counting the same number of elements
# since nothing changed in the meantime
viewMeetingTabPage.getMeetingAttachmentCount().then(function (newCount) {
expect(newCount).toBe(curCount + 1);
//expect(viewMeetingTabPage.getMeetingAttachmentName()).toBe('test-file.pdf');
});
});
});
currentFileCount could be considered a setup phase for the test so you can extract it to a beforeEach block:
var initialFileCount;
beforeEach(function() {
viewMeetingTabPage.getMeetingAttachmentCount().then(function(count) {
initialFileCount = count;
});
});
it('Should attach a file when a file is selected and OK button is pressed.', function () {
viewMeetingPage.clickAddAttachmentButton();
addAttchmentPage.attachFile();
addAttchmentPage.clickConfimAttachFileButton();
expect(viewMeetingTabPage.getMeetingAttachmentCount()).toBe(initialFileCount + 1);
});
Since protractor patches jasmine to wait between the test-blocks for the control-flow to empty, this would probably work.
Keep in mind expect is also patched to handle promises so you don't need to place it in a then.
UPDATE:
Actually, you shouldn't need the beforeEach above, it is supposed to work like that too:
var initialFileCount;
it('Should attach a file when a file is selected and OK button is pressed.', function () {
viewMeetingTabPage.getMeetingAttachmentCount().then(function(count) {
initialFileCount = count;
});
viewMeetingPage.clickAddAttachmentButton();
addAttchmentPage.attachFile();
addAttchmentPage.clickConfimAttachFileButton();
expect(viewMeetingTabPage.getMeetingAttachmentCount()).toBe(initialFileCount + 1);
});
It's called framing in the WebDriverJS User’s Guide.
Trying to do a simple scroll to the top of my page when the user clicks the 'edit' button. For some reason, when I try to set the $location.hash, it will not run any code following it.
It will put the value into the console, and in the browser address bar, but nothing after.
If you click 'edit' again, (the location value will be in the address bar, i.e. - sitename.com/#/send#top), and the rest of my code will run as expected.
Any ideas what I am doing wrong?
scrollToLoc = function(loc) {
$location.hash(loc);
$anchorScroll();
console.log(loc);
};
$scope.doEdit = function(item) {
scrollToLoc('top');
$scope.request = item;
};
I am allowing the user to press a Save button and so in the event method for that button I need to save all existing models in the collection and destroy any models that were deleted before the button was pressed.
What I would like to do is display an ajax gif while this is all happening. How can I find out when all model.save() and model.destroy() methods are finished?
Here is the method I call when the Save button is pressed:
Save: function() {
var response = confirm("Are you sure you want to save?");
if (response == true) {
// save items
var self = this;
this.collection.each(function(item) {
self.RemoveTempId(item); // if temp id exists remove it
item.save();
});
// destroy items in the trashcan
for (var i = this.trashCan.length - 1; i >= 0; i--) {
this.trashCan[i].destroy();
}
}
},
How can I tap into an event when they are all completed so I can hide my ajax gif?
Thanks..
Each of these method (save and destroy) returns a promise. You can wait for multiple promise to finish using the jQuery when method. e.g.:
$.when( model.save(), model2.destroy() ).then(function() { /* do stuff */ });
Of course this should be adapted to your used cases (because you loop through each model, so you'll probably use an array and .apply() the array of deferred on when), but you get the main idea.
Also I'd suggest separating the confirm dialog and the loading gif inside a view out of the model/collection. This will create a better separation of concern and a more manageable code.
An example with an array of deferreds:
var defs = [];
this.collection.each(function(item) {
defs.push( item.save() );
});
$.when.apply( null, defs ).then(function() {
/* everything is saved */
});
When user agrees to save after your prompt, just show your GIF Image on the page and set its position where you want to show it. Probably, you should display it at center of screen.
Pass a success and error handler in your save method as options hash and hide your GIF image there.
Take a look at Backbone Model save documentation
Some pseudo code goes like this:-
saveModel: function() {
//Show image now. Use CSS to make it visible.
$('#gifSelector').show();
model.save({ 'x':1, 'y':2}, // The default attributes in your model which we wanna save
success: function() {
alert('Model has been saved');
//Hide Gid image
$('#gifSelector').hide();
},
error: function(e) {
alert('Encountered some problem in saving model');
// Hide GIF image
$('#gifSelector').hide();
}
}
One Suggestion: Since you will be calling this method for each model and everytime we don't want to query DOM to get GIF image using its selector. Its better to store a global reference to it and show/hide it using that reference. It will be faster ;)