How to remove draggability from an element with Ext JS? - extjs

I have a div that I want to make draggable or not, depending on the state of some other stuff on my page. I seem to be able to easily make it draggable, but I can't seem to figure out how to best remove the draggability from the div.
I am making it draggable with:
var dd = Ext.create('Ext.dd.DDProxy', mydiv, 'myDDGroup', { isTarget: false });
And I've tried to then remove the draggability by removing the only group it's a member of
dd.removeFromGroup('myDDGroup');
and just destroying the dd object with
delete dd;
Neither of these seem to actually keep me from starting a drag on the element. I suspect I should be able to use the b4Drag override in some way to simply cancel a drag of my div before it even begins, rather than toggling the draggable state of the div at all, but I can't seem to find docs on how I might cancel the drag during the b4Drag call.
So, how can I make a div undraggable after I have already made it draggable?

Seems to be working for me.
Here is the JSFiddle http://jsfiddle.net/01gx33h0/
var dd = Ext.create('Ext.dd.DDProxy', 'test123', 'myDDGroup', { isTarget: false });
Ext.fly('btn123').on('click', function() {
dd.removeFromGroup('myDDGroup');
});
Can you give me the sample code where it is not working. And what version of ExtJs are using?

You have to unreg. Not removeFromGroup.
It just removes from group. But events are not removed on that element.
dd.unreg();
https://fiddle.sencha.com/#fiddle/1eun

When looking at something specific that needs to be dragged, you might consider that allowing dragging is something users expect, for general ease of use you might try the ondragstart="return, this could be appended to your images, or links like so:
<a ondragstart="return false" href="#link">link</a>.

Related

AngularJS - div still shows even without condition

Ok, I know that title could use some work, but I'm not sure how else to put it.
Here's the setup.
I have a (potentially) massive table that gets generated via an ng-repeat. All the rows need to be editable but, when the dataset is so large, all those bindings slow things to a crawl. I could literally be waiting upwards of 20 seconds for large sets to load!
We noticed that dumping the data in a read-only state significantly decreased the load time. So, we came up with the idea of loading it read-only, but, when the table row was clicked, it became editable. This is accomplished like so. I have two cells output. editableRow is initially false. When the row is clicked, editableRow becomes true. The idea being that, when editableRow becomes true, I see the other cell.
(proprietary code obfuscated)
<TABLE-CELL class="value-col" ng-if="readtime.editableRow === true">
<input type="text"
name="readingTime"
ng-model="<data model>"
ng-disabled="<param>"
ng-change="<function>"
ng-class="<classes>"
/>
</TABLE-CELL>
<TABLE-CELL class="value-col" ng-if="readtime.editableRow === false">
<input type="text"
placeholder="{{<data model>}}"
ng-class="<classes>"
/>
</TABLE-CELL>
The problem is, on the click, for a tiny fraction of a second both cells are visible. It really is only visible on the first click. Subsequent clicks still do it, but it goes so fast that the human eye can't catch it. I know it's there since I slowed everything down with a breakpoint on the mouse click. This also revealed that this happens as the value turns true - turning on the first cell, but the second one doesn't disappear in the same moment. So, it causes a "flicker" of sorts. This seems to happen outside my actual code, inside the jQuery, so I'm not sure how to short circuit it.
I've tried playing with using ng-show/hide instead, which worked a little bit, but also totally negated the time-saving aspect, since it actually renders everything, and it took a long time. I've also tried ng-cloak with no effect whatsoever.
The breakpoint that it keeps stopping on (when I told it to stop on event listeners to do with the mouse click) is the following code in jquery.js:
if ( !(eventHandle = elemData.handle) ) {
eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
jQuery.event.dispatch.apply( elem, arguments ) : undefined;
};
}
It hits that line about 4 times, and, on the last one, both cells are visible. Then, the second one disappears.
I'm out of ideas and would appreciate any thoughts on this.
I finally found an answer that works!
On this page: disable nganimate for some elements the answer right BELOW the accepted answer is what finally worked!
To disable ng-animate for certain elements, using a CSS class, which follows Angular animate paradigm, you can configure ng-animate to test the class using regex.
Config
var myApp = angular.module("MyApp", ["ngAnimate"]);
myApp.config(function($animateProvider) {
$animateProvider.classNameFilter(/^(?:(?!ng-animate-disabled).)*$/);
})
Usage
Simply add the ng-animate-disabled class to any elements you want to be ignored by ng-animate.

How to click on a deeply buried button in div classes via protractor. No id

I am trying to click a button that is buried in div classes in the code via protractor.
I am pioneering a protractor project for my work and have reached a point where I no longer know what to do. I have a button that is buried in div classes and is not allowing me to click. I have tried using mouseMove to get over to the coordinates of the button, I have tried using the className of the specific button, etc. The button does not have an id. The id is not the issue as I have tried clicking a different button, equally buried in divs, by it's id. I need to know how to get through the layers of divs in order to click the button because the rest of the tests will be dependent on it.
APPLICATION CODE:
::before
<dashboard-label>
<div class="att-topic-analysis-tabs">
<div class="att-button-group">
<button class="btn btn-default btn-lg att-close-topic ng-scope"
role="presentation" tabindex="-1"
ng-click="removeTopic(currentTopic.id)" translate>
Close Topic
</button>
</div>
</div>
PROTRACTOR TEST:
it('Closes Topic Successfully', function(){
//opens the first available topic
openTopic.click();
//checks that the URL contains 'topics' after 5 seconds
browser.wait(proExpect.urlContains('topics'), 5000);
var closeTopic = element(by.className('att-close-topic'));
//browser.wait(proExpect.elementToBeClickable(closeTopicButton), 5000);
console.log(closeTopic);
closeTopic.click();
browser.wait(proExpect.urlContains('home'), 5000);
});
As you can see, the Close Topic button is kind of buried in div classes and the standard click isn't working. Any info would be greatly appreciated
If the closeTopic locator is finding the element, but failing to click it, check to make sure there's only one matching element in the DOM, and that it's visible. My favorite way to check the DOM is just ctrl-F in Chrome inspector and paste the exact CSS that the test is using (.att-close-topic). And to check that what it's getting is visible, use
console.log(closeTopic.isDisplayed());
This can be a big gotcha in protractor, because it doesn't fail (only warns) when there are multiple matches on the page, and it defaults to the first match rather than the first visible match, which drives me nuts, because it's very rare that you want to do anything with a non-visible element on the page.
This will be partly opinion, but just to add a layer to the conversation...
Sometimes the solution to locating a troublesome element on the page is to go back to the developers and make the page more testable. I've seen testers spend hours or days crafting brilliant workarounds to access a stubborn element, and the end result was a fragile, complicated end-to-end test (and aren't they fragile enough already?).
Sometimes a 5-minute conversation with a developer can result in a quick change in the production code (e.g. add a unique ID) that avoids all that effort and yields a much better result, more stable, more simple. But this requires open conversation between the dev and test team, and a culture that values testing as a primary activity enough to make those testability changes to production code that is otherwise working just fine.
This is what you want to read to help you debug why your test doesn't work.
Also, you might want to start adopting await/async since the control flow will go away in the future.
http://www.protractortest.org/#/debugging
try this
var closebutton=element(by.css("[ng-click="removeTopic(currentTopic.id)"]"),
EC = protractor.ExpectedConditions;
Waits for the element to be clickable.checks for display and enable state of button
browser.wait(EC.elementToBeClickable(closebutton), 10000);
now use : closebutton.click();

Set zIndex programmatically on a Div in AngularJS

I have a number of Div's on a layout, each of them draggable, so there's the possibility of the user dragging them into positions where they will overlap.
I want to set the most recently made visible div to have a z-index value that's +1 from the last, and for this I'm using a $scope.nextIndex variable that's incremented each time one of the div's is made visible.
Each div has its own variable to track its own z-index value: $scope.one_zIndex, $scope.two_zIndex, $scope.three_zIndex, and each correctly gets assigned an incrementally larger value as each div is shown, hidden and shown again.
Each div has its own class: one_z, two_z, three_z
What I can't make work is assigning the variable to the z-index style on the divs themselves via the controller.
var myVar = document.getElementsByClassName("one_z");
If I log this to the console, I get what I expect - an array with one element [0]
[]
0 : div#one_z
length : 1
one_z : div#one_z
__proto__ : HTMLCollection
I would assume that I could set the z-index simply like this:
myVar[0].style.zIndex = $scope.one_zIndex;
However this throws an error:
Uncaught TypeError: Cannot set property 'zIndex' of undefined
What am I missing? Or is there a better way to accomplish this?
Here is a working plunker https://plnkr.co/edit/aaDipIWdqpajghc2F2Da?p=preview
You can set zindex via ng-style:
<div ng-style="{'z-index': $lastIndex;}">...</div>
This example completely useless in your case, but there is an example of ng-style usage. In your case I'd set index as property of you div element data source.
What wound up working was this:
First, I switched to IDs instead of classes, which likely didn't impact the solution but as each div was only ever going to exist once, IDs was the more correct way of identifying them.
Then, in the function that displays the div, I used this:
_.defer(function(){
jQuery('#one_z').css('z-index', $scope.one_zIndex);
});
There appeared to be an issue where I was showing the div and trying to set its z-index before the DOM had updated to include the div, so _.defer (I'm using Underscore.js) prevented the accessing of the z-index until everything had updated once, and it works.
As I mentioned in another comment - using ng-style wasn't working for me, and I had tried the _.defer with that approach as well initially without success.
For the record - I've used jQuery() instead of $() so it's clear in the code that this is a jQuery and not an Angular solution, and while I'd ideally have liked a purely Angular solution to this problem, this is clean enough for me, and doesn't do any DOM manipulation outside of Angular's purview that impacts the rest of the application in any way, it's purely display candy.

Using contenteditable with ng-model inside ng-repeat?

Here is my issue:
I am using ng-repeat to make a list of spans.
Each span has the contenteditable attribute and ng-model directive.
Everything works as expected (including two-way data binding), until I try to add a new item to the list.
<div ng-repeat="item in list">
<span ng-model="item.text" contenteditable></span>
</div>
<button ng-click="addItemToList"></button>
The methods look like this:
$scope.addItemToList = function () {
$scope.list.push({text: 'dummy text'});
}
or
$scope.addItemToList = function () {
$scope.list.splice(1, 0, {text: 'dummy text'});
}
When adding the new item to the list (push or splice), the DOM updates, but the last item is initialised empty, with no text whatsoever. The last item in the model list also empties out, even if I specifically push an element with text in it.
After a few tests, I've noticed that this only happens if the list's length is bigger after modifying it:
if I try to replace/modify/remove (not add) an element in the list, it works well.
I believe this has to do with the way contenteditable elements initialise in the DOM (I think they initialise empty, and somehow, the model empties out as well).
Has anyone encountered this problem before? If yes, how did you solve it / what workaround have you found?
Based on the angular docs related to ngModelController, it seems that there is not built-in support for two-way data binding with contenteditable elements, seeing as in the plunkr example they wrote their own contenteditable directive. You might be able to use a modified version of that as a workaround.
It looks to be a similar problem as this question and the contenteditable directive there looks similar to the contenteditable directive in the angular docs example.
I also found this directive on github that might accomplish what you are trying to do.
Edit: I did a new version of the plunk I posted in the comment above:
https://plnkr.co/edit/v3elswolP9AgWHDIPwCk
In this version I added a contenteditable directive that appears to be working correctly. It is basically a spin off of how the input[type=text] directive is written in angular, but I took out the places where it handles different types of input (since in this case it will just be text) and the places where it handles events that contenteditable elements don't even fire. I also changed it so that the $viewValue gets updated based on element.html() instead of element.val(). You might be able to use something like this as a workaround
The issue is old but that was the same problem for me today. (angular 1.5). My workaround was to add on blur update option: <td contenteditable data-ng-model="position.value" ng-model-options="{updateOn: 'blur'}"></td> somehow then model stopped getting be empty on initialize. I like using update on blur in many places (solves some performaces issues) so this is good for me, however it's some kind of trick.

How to scroll to a particular record in grid?

Previously, I used persistent grid plugin, until I found out that it caused some terrible slowdown - about 3-4 extra seconds of grid rendering (~20 columns and 300 rows). So, I do not want all this plugin functionality, the only thing I want to have is scrolling to a selected record in grid (there may be a lot of records selected, so scrolling to the first one is enough). I try to do it like this:
.... a lot of code ...
rowIndex=grid.store.indexOf(grid.getSelectionModel().getSelection()[0]);
record=grid.getSelectionModel().getSelection()[0];
grid.store.remove(record); // <- I remove it, because its content has changed
grid.store.insert(rowIndex,Ext.create('GridModel',json.items[0])); // <- I insert
// it back with new values
grid.getSelectionModel().select( rowIndex ); // <- This works, I see a checkmark
grid.getView().focusRow( record ); // <- This is not working
....
Instead of what I expect to see, I see scrolling to the top of the grid.
EDIT
This is not working:
Ext.fly(grid.getView().getNode(rowIndex)).scrollIntoView(); // instead of focus
Also not working:
var rowEl=grid.getView().getNode(rowIndex);
rowEl.scrollIntoView(grid.el, false);
So, what to use instead of focus?
EDIT
Setting deferRowRender to false in grid config also has no effect. Still, grid scroll to the very top of its view.
EDIT
Well, as it turned out, focusRow had no effect because of the grid.store.sync call. So, I put this routine inside sync callback function and now it is working.
In extjs 4 the solution might be use method scrollBy() http://docs.sencha.com/extjs/4.2.6/#!/api/Ext.Component-method-scrollBy
In Extjs 5: try the methods getScrollable().scrollTo(...);
http://docs.sencha.com/extjs/5.1.3/api/Ext.grid.Panel.html#placeholder-accessor-getScrollable
http://docs.sencha.com/extjs/5.1.3/api/Ext.grid.Panel.html#method-scrollTo
In Extjs 6: try the methods getScrollable().scrollToRecord(...);
http://docs.sencha.com/extjs/6.2.1/modern/Ext.grid.Grid.html#method-getScrollable
http://docs.sencha.com/extjs/6.2.1/modern/Ext.grid.Grid.html#method-scrollToRecord
Although on a different issue, this post may be useful: How to scroll to the end of the form in ExtJS
try below code
grid.getView().focusRow( record );
Try this:
var numIndex=** //this is record index
var x=grid.getView().getScrollX();
grid.getView().scrollTo(x,numIndex*21); //x,y --> unit is pixel

Resources