-
Notifications
You must be signed in to change notification settings - Fork 3.4k
fix(panel): clickOutsideToClose with propagateContainerEvents #9886
fix(panel): clickOutsideToClose with propagateContainerEvents #9886
Conversation
var found = false; | ||
angular.forEach(elems, function(elem) { | ||
if (elem === sourceElem) { | ||
found = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this? It quits early when it finds a match and removes the extra variable.
var findSourceEl = function(els, sourceEl) {
for (var el, i = 0; el = els[i]; i++) {
if (el === sourceEl) {
return true;
}
});
return false;
};
|
||
// We check if the sourceElem of the event is the panel element or one | ||
// of it's children. If it is not, then close the panel. | ||
var found = findSourceElem( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
El instead of Elem. We use el throughout this file, so it's strange to switch naming conventions here.
|
||
openPanel(config); | ||
|
||
clickOutsideOfPanel(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be clickPanelContainer? Or can clickPanelContainer be updated so you're not duplicating logic. (The only thing that's changing is the element you're clicking on. Maybe something like this?
function clickPanelContainer(rootEl) {
rootEl = rootEl || document.body;
const selector = '.md-panel:not(._md-panel-backdrop)';
angular.element(rootEl).find(selector).parent().simulate('click');
angular.element(rootEl).find(selector).parent().simulate('mousedown');
angular.element(rootEl).find(selector).parent().simulate('mouseup');
flushPanel();
}
Benefits of this version is that you don't need the panelRef, which removes one of the if statements. I know this version can replace the current one and you won't need to change any tests.
or
function clickPanelContainer(container) {
container = container || angular.element('.md-panel-outer-wrapper');
container.triggerHandler({
type: 'mousedown',
target: container[0]
});
container.triggerHandler({
type: 'mouseup',
target: container[0]
});
flushPanel();
}
639cdaf
to
f0ad663
Compare
|
||
// We check if the sourceEl of the event is the panel element or one | ||
// of it's children. If it is not, then close the panel. | ||
var found = findSourceEl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could simplify it and avoid the loop if you did something like this:
var found = sourceEl === self.panelEl[0] || self.panelEl[0].contains(sourceEl);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was looking for the .contains()
method and didn't realize that I would have to access the element to get to it. Good catch and I appreciate you showing it to me.
clickOutsideToClose: true | ||
}; | ||
|
||
openPanel(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make the test slightly more robust if you had a check that the PANEL_EL
exists, right after opening it. This should avoid cases where the test will pass, if the openPanel
function didn't open it up for some reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The open panel result is pretty well tested in the tests that proceed this one. You will also notice in the test right before this one, should close when clickOutsideToClose set to true
does not expect the PANEL_EL
to exist before it expects it to be closed. I went with that understanding to write this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While it's true that the opening logic is well tested, we should try to keep the tests as independent as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@crisbeto I go back and forth on this one. Because the open existence is tested earlier, we get a better test signal when opens fails because the failure is in the test that tests open. If we write it in every test, then all will fail and the messages don't point to the actual problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't say it's necessary for every test, but it makes sense for this one since the test would fail if there isn't an open panel. This may be down to personal preference, though.
if (!panelRef) { | ||
return; | ||
} | ||
|
||
var container = panelRef.panelContainer; | ||
var container = container || panelRef.panelContainer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bad practise to have variables with the same name as function arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should actually read as container = container || panelRef.panelContainer
. I forgot to remove the var
before it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, it makes sense without the var
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ThomasBurleson I think that there was some confusion as we extended this function. Previously, the container variable was declared internally and assigned to the panelRef.panelContainer
. Now, you are able to pass in a container to click on. But, if you don't pass one in, it needs to still assign it to the default panelRef.panelContainer
.
f0ad663
to
360d631
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
360d631
to
1f18e4c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
clickOutsideToClose: true | ||
}; | ||
|
||
openPanel(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@crisbeto I go back and forth on this one. Because the open existence is tested earlier, we get a better test signal when opens fails because the failure is in the test that tests open. If we write it in every test, then all will fail and the messages don't point to the actual problem.
|
||
openPanel(config); | ||
|
||
clickPanelContainer(angular.element(document.body)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move the angular.element
part to the clickPanelContainer? I don't think it particularly matters for this test, so it seems to fit better in the helper method.
I'm wondering if we want something like getElement
to make this more flexible.
material/test/angular-material-spec.js
Line 287 in 72d0685
function getElement(el) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went ahead and added this one, as I thought that it was a more extended implementation and useful.
…Events If both the `clickOutsideToClose` and `propagateContainerEvents` parameters are set to true within the panel configuration, then the panel will be closed when a click happens outside of the panel. Fixes angular#9388
1f18e4c
to
76bb9b6
Compare
@ThomasBurleson This is ready for merge. |
@ThomasBurleson Checking on the status of this PR. |
If both the
clickOutsideToClose
andpropagateContainerEvents
parameters are set to true within the panel configuration, then the panel will be closed when a click happens outside of the panel.Fixes #9388