I have a table that when I click on a row, in a side div I display the details. I have created an event on the row (tr) that is fired every time that row is clicked. The problem I have is that the event is being fired multiple times. It is acting as if a new view is being created everytime the event is fired, but a new view is not being created. Here is the code:
GroupView = class App.GroupView extends Backbone.View
template: App.Utils.getTemplate 'group'
selectedId: 0
events:
'click tr': 'selectGroup'
selectGroup: (e) ->
thisEl = $(e.currentTarget)
$(thisEl).closest('tr').siblings().removeClass 'selected'
$(thisEl).closest('tr').addClass 'selected'
#selectedId = $(thisEl).data().id
#getGroupDetails #selectedId
render: ->
$(#$el).html #template
groups: #collection.models
if #selectedId is 0
firstRowEl = $(#$el).find('tr:first')
$(firstRowEl).addClass 'selected'
#selectedId = $(firstRowEl).data().id
#getGroupDetails #selectedId
getGroupDetails: (id, platform) ->
$('<img/>',
src: 'img/ajax_loader_2.gif'
class: 'ajax-loader'
).appendTo '.group-details'
renderGroupDetails id
groupDetails = new GroupDetailsView
el: '.group-details'
model: groupDetailsModel
renderGroupDetails = (id)->
groupDetails.el = '.group-details'
groupDetails.stopListening groupDetailsModel
groupDetails.listenTo groupDetailsModel, 'change', ->
groupDetails.model =
groupDetails: groupDetailsModel.toJSON()
groupDetails.render()
groupDetailsModel.fetch
data:
id: id
processData: true
The issue is that when I use the groupDetails.stopListening groupDetailsModel, the multiple event firing issue is resolved but then NONE of the events in the groupDetails view is being fired.
Any help is appreciated.
Cheers,
Kianosh
So, giving you a specific answer is difficult: the code you've pasted is a bit hard to follow, and seems like it might be missing bits (eg. what's a groupDetailsModel? Does it have any logic that affects it's view?). That's ok though, because I think what you need here is more debugging help than a specific answer.
If I understand you correctly, your problem is that groupDetails.render() is being invoked extra times, and you're not sure why or what is invoking it: is that correct? If so, your trusty debugger can answer this in a matter of seconds.
NOTE: Everything I'm about to say applies to Chrome (with the built-in developer tools up) or Firefox (with the Firebug extension up) for sure. It probably applies to other browsers with their tools too, I just can't say for sure since I don't use them.
Approach #1: Debugger
With your debugger up, add a debugger; line as the first thing inside your GroupDetails.prototype.render method. This will make your browser pause on that line whenever it hits it. While its paused you can check the "call stack" on the right-hand side, and that will show you exactly what bit of your code just called that render. You can also use the debugger to inspect the values of the different variables in your environment to try and understand why your code is calling render.
Approach #2: Console.trace
If you're not a fan of using the debugger, there's another tool that's also perfect for answering this sort of question. Simply add console.trace() as the first line in your render method, then run your code as normal. This time your browser will log (to the "console") a stack trace generated from that point in the code. This stack trace is similar to the call stack that you can see when you use debugger, and thus it will tell you exactly what code invoked the render each time.
Hope that helps.
Related
Alright, so I thought this would be easy but I've spend a few hours searching and trying different methods with no avail. I need to tell protractor to only click on a button when it is present. To water it down basically my test checks if a certain value is present on a page. The page can be in one of two states, automatic mode, which contains my value I'm testing or design mode, which contains other values which are irrelevant for this test. If its in design mode, we first need to click on automatic mode which produces a prompt asking us if we are sure we want to continue and switch to automatic mode - this prompt contains the continue button I need to check for and click. If the page is already in automatic mode however, I don't need to perform this check, I can proceed to validate weather or not my value is present. Basically I tried this:
if (continueButton.isDisplayed()) {
continueButton.click();
}
what happens I get a "No element found using locator:..." error. I tried a few different ways such as using isElementPresent, and some of the expected condition options but more or less I get the same results. How can I achieve this scenario where my test checks if a button is present and clicks it, and if it isn't present continues with the test.
You can achieve this by using promises.
continueButton.isDisplayed().then(function (isDisplayed) {
if(isDisplayed){
continueButton.click();
}
});
browser.wait() and elementToBeClickable Expected Condition is exactly what might help:
var EC = protractor.ExpectedConditions;
browser.wait(EC.elementToBeClickable(continueButton), 5000);
continueButton.click();
How to get to $(document) in the onReady method ?
I've tried with smoothState.cache[smoothState.href] but couldn't make it works.
(fantastic plugin)
Thanks
I'm assuming you want to get at the document for the new page that's being loaded. Technically, $(document) exists in onReady, and it's the first document you visited on the site. After that, smoothState just dynamically updates it by swapping out content. So whatever existed on the previous page you were viewing is there as normal. Once the line $container.html( $newContent ); runs in your onReady method (assuming your code follows all the smoothState examples), you new content should be available.
However, if you want to get at the actual, full document for the new page that got loaded up, not just what's contained in your wrapper div that gets swapped out, it's contained in smoothState.cache[smoothState.href].doc. It's got the header, the body, everything.
A little reading of the smoothState source code shows that you can pull it into a useful format this way:
var $newDoc = $("<html></html>").append( $(smoothState.cache[smoothState.href].doc) );
At this point, you can run find queries or whatever you need to go look through things.
Before to open a bug to the Qt project, I'd like to ask you if I'm doing something wrong or the Qml Calendar is really going crazy.
It follows the code which can be used to test it:
import QtQuick 2.5
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
Window {
visible: true
width: 1024
height: 768
ColumnLayout {
anchors.fill: parent
anchors.margins: 8
Calendar {
id: calendar
Layout.fillWidth: true
Layout.fillHeight: true
weekNumbersVisible: true
selectedDate: new Date("2015/01/01")
frameVisible: true
focus: true
onVisibleMonthChanged: visibleMonthChangedRef.currDate = visibleYear+"/"+visibleMonth
onVisibleYearChanged: visibleYearChangedRef.currDate = visibleYear+"/"+visibleMonth
}
Label {
id: visibleMonthChangedRef
Layout.fillWidth: true
property string currDate: ""
text: "onVisibleMonthChanged -> " + currDate
Component.onCompleted: font.pointSize = font.pointSize*2
}
Label {
id: visibleYearChangedRef
Layout.fillWidth: true
property string currDate: ""
text: "onVisibleYearChanged -> " + currDate
Component.onCompleted: font.pointSize = font.pointSize*2
}
}
}
Easy going, start the application and you'll see a calendar as well as a couple of labels that report information about the visibleMonth and the visibleYear as provided by the Calendar component.
Those labels are filled accordingly to the onVisibleYearChanged and onVisibleMonthChanged of the Calendar.
The selected date is 2015/01/01.
Well, go back of a month towards the 2014.
The onVisibleYearChanged looks to be right while accessing the visibleMonth and visibleYear properties of the Calendar, while the onVisibleMonthChanged looks to me as living in a far future.
Now, try to move on of a month towards the 2015.
Again, while the onVisibleYearChanged is still behaving the right way, the onVisibleMonthChanged is accessing a Calendar component that is sitting in the past.
You can go back and forth over the new year and a function that is reacting to the signal onVisibleMonthChanged will never behave properly for it looks to me as invoked once all the internal properties have not been properly set yet.
That said, am I doing something wrong and thus the problem is within my code (of course, the one above is a small example from a more complex project) or I've really found a bug in the 'Calendar` component and I should proceed opening a ticket to the Qt project?
Even though it looks a bit strange to me asking to modify a component, being notified that it's updated, thus find that my changes have been only partially set (a kind of work in progress notification), that's it.
It seems that the error was in my expectations. :-)
Once the month moves on or back over the year (that is, from December to January and vice versa), the Calendar component correctly updates the property visibleMonth and the property visibleYear.
Anyway, the are no guarantees that the corresponding signals (onVisibleMonthChanged and onVisibleYearChanged) are emitted once the internal representation has been updated as a whole.
Actually, the former is emitted when the changes to the second property are still pending, thus querying the visibleYear property in a listener ends with the wrong year (or at least, a one not updated yet).
As an example of solution, the user of the component can work around this odd behavior by attaching a listener to both the signals, even though I strongly suspect the out there a better solution is waiting for me.
I'll manage to find an alternative approach.
Thank you for all of your responses.
I'm trying to create an NG app where parts can be enabled/disabled dynamically. The idea is to have an "admin" page, where parts of the app can be enabled or disabled, and then see new functionality appear, in the form of an adjusted menu at the top of the page, and matching routes, controllers, etc loaded into the app (I'm using SocketStream w/ NG).
The first step was to add / remove routes dynamically, for which I found a solution at https://stackoverflow.com/a/13173667 - working well, as far as I can tell.
Next, adding items to the menu bar - easy with ng-repeat on ul/li items.
So the app adjusts its menu and recognizes the corresponding route. So far so good.
The problem comes with registering a controller. I'm calling myApp.controller('SandboxCtrl',[...]) with proper args (same as what worked when initialising statically on startup), but the controller does not appear to get loaded or inited properly. Navigating to the newly added route generates errors such as:
Error: Argument 'SandboxCtrl' is not a function, got undefined
assertArg#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:973
assertArgFn#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:984
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:4638
update#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:14007
$broadcast#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:8098
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7258
wrappedCallback#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:6658
wrappedCallback#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:6658
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:6695
$eval#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7848
$digest#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7713
$apply#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:7934
#http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.js:5433
I'm currently at a loss on how to proceed. I've not been able to find a solution on the web. The app is too large to put in a jsFiddle, but I can commit the last changes on GitHub if needed.
Questions: is this feasible? what can I do to debug this? any examples I could look at?
EDIT: The code is now at https://github.com/jcw/housemon (needs node/npm/redis). It's easy to reproduce the problem: launch with "npm start", browse to localhost:3333, go to admin tab, click on "jcw-sandbox" and then "Install". Top menu will update with new a "Sandbox" entry. Clicking on that entry generates the error shown above.
Oh, almost forgot: relevant code is in client/code/app/main.coffee and client/code/modules/routes.coffee ...
The answer turns out to be two-fold:
the NG calls were made from SocketStream RPC callbacks, and had to be wrapped in $scope.$apply calls - my bad, didn't know about this SS/NG interaction
the rest of the solution was outlined by #matys84pl - pick up $controllerProvider (and $filterProvider) early on, so they can be called at a later time instead of the normal "app.controller" and "app.filter" members, which don't seem to work anymore later on
Example code in GitHub, I'll link to a specific commit so this answer stays valid:
https://github.com/jcw/housemon/commit/f199ff70e3000dbf57836f0cbcbb3306c31279de
I've came across this issue today and I think I might need some help. We are using 1.6.1 version of Dojo, but this is cross version issue.
Steps to reproduce the following issue are pretty simple:
click the dojo doc link for Filtering Select dijit.form.FilteringSelect
On the documentation page, click the first FilteringSelect sample
In the Codeglass window sample, click the filteringselect and add "x" to "California", thus bringing it to invalid state
While focused, delete the "x" letter.
and here comes the problem. Technically the value is correct, but the dijit is still like in error state (unless it loses focus).
I'd like to get the dijit react and render correctly straightaway I delete the character causing the invalid state without losing focus.
Any ideas for the workaround?
Thank you.
ok. for eveyryone else interested the solution was 'quite' simple, just use the dijit.form.FilteringSelect._refreshState() .The underscore prefix is might not be someone's cup of tea but that was the only way to get it in correct state.
in our case it was a bit tricky as we are using the dojox.data.QueryReadStore wrapped in our own object and I needed the proper trigger which I've found in connecting to onComplete event of the inherited fetch() method.