I want this element to self hide once clicked. How do I target self with Alpine, and string 2 #click events together?
<div #click="tagify.addTags(['hardware'])">hardware</div>
There are multiple ways you can handle this,
you can target self by the event.target as in method 1, other methods a just alternative approaches to hide the element.
Method 1 - Set the style inline in the click handler
<div #click="tagify.addTags(['hardware']); event.target.style.display='none';">hardware</div>
Method 2 - Use x-ref
<div x-ref="hardware" #click="tagify.addTags(['hardware']); $refs.hardware.style.display='none';">hardware</div>
Method 3 - Use x-show with a variable
<div x-data="{showHardware : true}">
....
<div x-show="showHardware" #click="tagify.addTags(['hardware']); showHardware = false">hardware</div>
</div>
This works great for me
<button #click="open = true; event.target.style.display='none';" x-text="'Show more'"></button>
Related
I have a table with a list of contacts as seen in the image. I also have an event that gets triggered when a row is clicked so it can show the selected contact detail (I am using angular NGIF directive to show and hide the detail)
The thing is because my google input is placed inside an NGIF block, when user expands the contact detail and tries to type in it, the predictions (pac-container) is showing on the row that I clicked (within the table) rather than underneath the google input autocomplete search box.
I tried to manipulate the css of the class pac-container but I couldn't figure out a way to override the css of that class.
Here is my the html of my autocomplete search box
<div *ngIf="showGoogleAddress" class="mg-b-10" fxLayoutGap="10px" fxLayout="row" fxLayout.xs="column" fxLayout.sm="column" fxFlexFill>
<div fxFlex>
<mat-form-field appearance="outline" class="form-field">
<mat-label>Google Address Search Box</mat-label>
<input [debounceTime]="500" ngxAutocomPlace autocomplete="off" (selectedPlace)="placeChanged($event)" placeholder="ex: Phoenix, Arizona" matInput #googleAddress="matInput" >
<mat-icon matSuffix>location_on</mat-icon>
<mat-hint>Search for compolete address, or city</mat-hint>
</mat-form-field>
</div>
</div>
also, here is a screenshot of the entire form after expanding the detail
If the google autocomplete box was outside the NGIF, then it will render the predictions just fine without an issue. It seems that because I am using NGIF directive, the google component is not able to determine the right position (calculate the right position) to render its predictions..
When I tried
.pac-container {
position: absolute !important;
z-index: 100000;
}
it did not work.
I had to go with a DOM Manipulation way using JS.. so I added a (keyUp) event handler on google search box with a method to calculate the position like the following:
adjustResPosition() {
setTimeout(() => {
var gSearchBar = document.getElementById('googleBar');
var topPos = (gSearchBar?.getBoundingClientRect().top || 0) + window.scrollY + 25;
var leftPos = (gSearchBar?.getBoundingClientRect().left || 0) + window.scrollX;
var gPreds = document.querySelector('.pac-container');
gPreds?.setAttribute('style', `top: ${topPos}px; position: absolute!important; width: auto; left: ${leftPos}px`);
}, 600);
}
The reason why I put setTimeout to 600ms is because I have a debounce 500 ms each until it grabs the next predictions and put it in the pac-container div
Note, this is not an optimal solution and it can be improved with ViewChild or ElementRef
Is there any Clarity element to wrap the container of clr-datagrid element in html? Please suggest me the solution to wrap the clr-datagrid using clarity element.
In the below instead of "div" element, i want to use clarity element. So that clrDgLoading will work. Here now it is not working as div is not known to clrDgLoading.
<div [clrDgLoading]="loading">
<clr-datagrid *ngIf="some condition which i need">
....................
</clr-datagrid>
</div>
I want loader to work first and then i will add my condition to clr-datagrid whether to show/hide the table or not(depends on the data presence).
I would suggest to use a spinner like the angular material spinner or the ngx-spinner for progress before loading the datagrid.
Example material spinner:
<mat-spinner></mat-spinner>
Example ngx-spinner:
<ngx-spinner
bdOpacity = 0.9bdColor = "#333"size = "medium"color = "#fff"type = "line-spin-clockwise-fade"[fullScreen] = "false"
>
<p style="color: white" > Loading... </p>
DEMO ngx-spinner
i am using syncfusion pager, dropdownlist in our application
please open the below link.
https://stackblitz.com/edit/angular-nv6myv?file=src%2Fapp%2Fapp.component.html
data will change based on the number of items selected from dropdown.
after selecting the 20 items from drop down go to bottom of the page by scrolling.
drop down list is showing bottom of the drop down box. but i want to show dropdown list items always top of the dropdown box.
Please provide any solution.
i just saw your code on your link, and i tried this:
<div class="container-fluid">
<div class="card" *ngFor="let student of tempArray">
<div class='card-body'>
<p class="text-truncate">{{student.name}} {{student.standard}}</p>
</div>
</div>
<br/><br/><br/><br/><br/>
<div class='card'>
<div class='card-body'>
<div class="fixed-footer" *ngIf="students.length > paginationData[0].value">
<ejs-pager [pageCount]="3" [pageSize]="value" (click)="selectedPage($event)"
[totalRecordsCount]='students.length'></ejs-pager>
<ejs-dropdownlist [dataSource]="paginationData" [fields]="fields" (change)="valueChange($event)" [popupHeight]=150 [value]="value"></ejs-dropdownlist>
</div></div>
</div>
</div>
what i did here is that i put the list items and the drop down box on a separate card.
it's a little messy, just please arrange the indentions.
In the dropdownlist open event, you can get the popupHight and set a negative value into popup offsetY property, refer to below code.
onddlPopupOpen(event: PopupEventArgs, ddlObj) {
event.popup.offsetY = -(parseInt(ddlObj.popupHeight));
event.popup.collision = { X: 'fit', Y: 'fit' };
event.popup.dataBind();
event.popup.refreshPosition(ddlObj.element, false);
}
This will open the popup in the top.
Sample
I have an anglarJS project that has a horizontal navigation bar. Each element in the navigation bar is a category and uses an angularJS dropdown directive to show the subcategories for that category.
I would like the drop down to fill the whole screen from left to right. Currently the drop down determines it's width from the css "min-width" property. This does not solve my desire for the drop down menu to fill the whole screen I have seen some websites do this, and was wondering if there is a way to force my dropdown to fill the whole screen from left to right.
Here is the html for the page/drop down including the css that specifies the dropdown width.
Here is a picture of the dropdown again. I added blue arrows to indicate what I mean when I want the drop down to fill the whole screen.
The pictures are pretty high resolution and show you all the details. The page is rather complex to try and replicated in a plunker.
The whole thing needs to be responsive as well, and is based off of Bootstrap 3 and AngularJS Bootstrap.
Thanks for any help you can give!
David
I found a solution for the problem.
I created a button group that floats left that is on the same row as the button group in the center. The button group that floats left only contains one button, and that button has it's visibility set to hidden.
You have the dropdown attached to this button, rather than the ones in the center, since the dropdown won't start any farther left than the beginning of the button it is attached to.
<div class="pull-left">
<div class="btn-group" dropdown is-open="isOpen">
<button type="button" style="visibility: hidden" class="btn btn-link dropdown-toggle filter-criteria-variety-category-name" dropdown-toggle ng-disabled="disabled">
<span class="caret"></span>
</button>
<div class="dropdown-menu top-level-category-drop-down-standard" ng-style="{{windowWidth}}" ng-click="$event.stopPropagation()" >
<div ng-click="$event.stopPropagation()" ng-mouseleave="close()" ng-mouseenter="keepOpen()">
<div ng-if="currentCategory != undefined">
<horizontal-menu-inner close-drop-down-menu=$parent.closeDropDownMenu top-level-category=$parent.currentCategory></horizontal-menu-inner>
</div>
</div>
</div>
</div>
</div>
And for the centered button group that contains your categories you want to trigger the dropdown you pass the 'ioOpen' variable into the centered button directive as an attribute.
<div class="text-center">
<div class="btn-group">
<div class="horizontal-top-level-category" ng-repeat="topLevelCategory in categoryNavigationGraph">
<horizontal-top-level-category is-open=$parent.isOpen current-category-id=$parent.currentCategoryId top-level-category=topLevelCategory></horizontal-top-level-category>
</div>
</div>
</div>
You then have that directive set up to close or open the drop down depending on whether the mouse enters or leaves the button in that directive
<button ng-mousemove="activeMenuItemm()" ng-mouseleave="close($event)" ng-mouseenter="open()" type="button" ng-class="{'filter-criteria-variety-category-name-hover': filterCriteriaCategoryActive}" class="btn btn-link dropdown-toggle filter-criteria-variety-category-name" ng-disabled="disabled">
{{topLevelCategory.text}}
The tricky part is not having the dropdown close when you hover down from the centered button onto the dropdown
I did this by figuring out if the mouse was leaving from "down", which should not close the dropdown, or other, which should from the last position, which was calculated In the centered button directive link function:
link: function (scope, element) {
init();
scopeLevelFunctions();
function init(){
calculateBoundry();
}
function scopeLevelFunctions(){
scope.calculateElementBoundry = function(){
calculateBoundry();
}
}
function calculateBoundry(){
var boundry = element[0].getBoundingClientRect();
scope.boundry = boundry;
scope.topBoundry = boundry.top;
scope.bottomBoundry = boundry.bottom;
scope.leftBoundry = boundry.left;
scope.rightBoundry = boundry.right;
}
},
The open function triggered by mouseenter sets the boundry, which the close calculates from that value to see if this is a mouseleave that is leaving down
$scope.open = function(){
$scope.calculateElementBoundry();
$scope.currentCategoryId = $scope.topLevelCategory.categoryId;
$scope.filterCriteriaCategoryActive = true;
$scope.timeoutPromise = $timeout(function() {
$scope.isOpen = true;
}, 150);
};
$scope.close = function($event){
$scope.lastPosition = {
x : $event.clientX,
y : $event.clientY
};
var deltaX = $scope.lastPosition.x - $event.clientX,
deltaY = $scope.lastPosition.y - $event.clientY;
if($event.clientY >= ($scope.bottomBoundry - 8))
$scope.direction = "bottom";
else
$scope.direction = "other";
if($scope.direction != "bottom"){
if($scope.timeoutPromise != undefined)
$timeout.cancel(this.timeoutPromise);
$scope.isOpen = false;
$scope.filterCriteriaCategoryActive = false;
}
else{
if($scope.isOpen == false && $scope.timeoutPromise != undefined){
$timeout.cancel(this.timeoutPromise);
$scope.filterCriteriaCategoryActive = false;
}
}
I put the timeout in there so that if the user is just scrolling to bottom of the screen the drop down does not just appear. I cancel the timeout if they mouseleave and the drop down is not open.
The dropdown gets different data in it because the centered category directive has an attribute "categoryId" that is shared with the directive that the dropdown is located in. As that categoryId is changed that directive determines what that new categories submenu should be and feeds that into the dropdown.
I know how wide the dropdown should be because in the directive that contains the dropdown/invisible button I calculated the window width:
var width = $window.innerWidth;
$scope.windowWidth = "{'min-width':" + width + "}";
and on the dropdown I use ng-style to set this width
ng-style="{{windowWidth}}"
I have multiple eventlisteners to my div: dragstart, dragenter, dragover, dragleave, drop and dragend.
To attach them to my div, I use the body onload function:
function addListeners()
{
var cols = document.querySelectorAll('#columns .column');
[].forEach.call(cols, function(col) {
col.addEventListener('dragstart', handleDragStart, false);
col.addEventListener('dragenter', handleDragEnter, false);
col.addEventListener('dragover', handleDragOver, false);
col.addEventListener('dragleave', handleDragLeave, false);
col.addEventListener('drop', handleDrop, false);
col.addEventListener('dragend', handleDragEnd, false);
});
}
but this code adds the eventlistener to the whole div. I only want the header of the div to respond to these events:
Now I can click on any part of the div and drag it, but I only want to be able to click on the black part (header) of the div to move it. The black part is a simple header in CSS.
HTML
<body onload="addListeners()">
<div id="columns">
<div class="column" draggable="true"><header>A</header>Textual information inside div A</div>
<div class="column" draggable="true"><header>B</header>Textual information inside div B</div>
<div class="column" draggable="true"><header>C</header>Textual information inside div C</div>
</div>
</body>
A JSFiddle of my full page can be found here.
How can this be done?
You need to add EventListeners to your header elements.
but those event listeners will work only when your headers are draggable=true
so by adding EventListeners to the header and making it draggable=true you can start to drag it.
But there is one problem now, you don't want to drag just the header, but its entire content i.e its parent div. and you want to swap it with the parentNode.innerHTML of the other header(upon which you are dropping).
so, you need to do this:
add events to the header element,
perform all the other operation i.e. grabbing and then swapping innerHTML on the parent of the header i.e. this.parentNode
also when you perform the innerHTML swap, all the event listeners are lost,because now, the very draggable element is recreated, so you will have to call your event binding function addListeners() again.
working fiddle