How to position google autocomplete predictions? - css

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

Related

Change the height of a dragged item before drop using angular material drag and drop

I tried to change the height of the dragged object using angular material drag and drop. I have tried to change the class name of the dragged div using cdkdragstart event and adjusted the height in the css.
app.component.html
<div cdkDropList #nameDragDrop="cdkDropList" [cdkDropListData]="names" [cdkDropListConnectedTo]="['nameTime']" (cdkDropListDropped)="drop($event)">
<div *ngFor="let iteration = index" cdkDrag (cdkDragMoved)="dragStarted($event,iteration)" (cdkDragEnded)="dragEnded(iteration)">
<div class="nameDiv" [ngClass]="{'reduceHeight': hideImageIcon === iteration, 'scenes': hideImageIcon !== iteration }">
</div>
</div>
</div
app.component.ts
dragStarted(event,index:any) {
this.hideImageIcon = index;
}
drop(event: CdkDragDrop<String[]>) {
if (event.previousContainer.id === event.container.id) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
}
I tried to get the dragged index using drag started method and assigned the index to the variable and change the class name in html file based on the condition.
app.component.css
.reduceHeight{
height:27px!important;
}
.show{
display: block!important;
}
.hide{
display: none!important;
}
Here the problem is, height is not getting changed while dropping the item. I want to change the height of the dragged object on start of the drag event. Is there any event is available in angular material drag and drop to change the height of the dragged object?
How about customizing drag preview https://material.angular.io/cdk/drag-drop/overview#customizing-the-drag-preview

Use CSS to move cursor to another element

I'm trying to move the location of the cursor (mouse pointer) when an element is brought into view.
Let's say I have a button at the top of screen that, on click, opens a somewhere else on the screen. They are not connected in the doc flow (the is position: fixed>
When I show the new item, I want the mouse cursor to move to the newly displayed element, e.g. to the close button inside of it. I added a call to focus() but not working...
function myClick(idName) {
let listOfBios = document.getElementsByClassName("contents");
const len = listOfBios.length;
let elemName = "Content_" + idName;
let elem = document.getElementById(elemName);
elem.focus();
for(let i = 0; i < len; i++) {
let theBio = listOfBios[i];
if(theBio != elem){
//alert(elemName);
theBio.classList.remove("show_contents")
}
}
elem.classList.toggle("show_contents", 1);
elem.focus();
}
Assume that the rest of the code works, so I definitely have the right element ad toggle() is working.
You will need JS to achieve this. See below for example with vanilla JS.
in your view:
<input type="text" id="myTextField" value="Text field.">
in JS:
document.getElementById("myTextField").focus();
Check this fiddle:
https://jsfiddle.net/jz7v53tL/
Looks like it can't be done with just CSS and JS. Trying to close this out, I hope this is how.

Bootstrap popover - move it to the left/right side

I want to relocate my bootstrap popover in the left side, i.e. I want to move the whole popover in the left side, while the white arrow would stay in one place.
I would like to have the effect which is on google.com website, when you click blue icon you see popover but its content is relocated while the white arrow is located under the user.
I know that I can use something like this:
.popover {
top:0 !important;
margin-top:10px;
}
Unfortunately, it relocates the whole popover altogether with white arrow.
What I have now (popover is on the right side and there's no place between screen edge and my popover)
What I want to have (small distance between popover and monitor's edge):
“I want to change the position of content of this popover so that this
arrow will be placed further on the left„
When the popover is shown the arrow position is calculated in Tooltip.prototype.replaceArrow based on width/height and placement. You can force a specific position with this CSS :
.popover .arrow {
left: 90px !important; /* or 45% etc */
}
But that will affect all popovers. Popovers is injected and removed to and from the DOM, and there is by default no way to target visible popovers individually. If you want to style the arrow on a specific popover, a workaround is to hook into the shown.bs.popover event, detect which popover that is being shown, and style the arrow for that popover if needed. Example :
.on('shown.bs.popover', function() {
var $popover = $('.popover')[0];
switch ($(this).attr('id')) {
case 'a' : $popover.find('.arrow').css('left', '10px');break;
case 'b' : $popover.find('.arrow').css('left', '40%');break;
case 'c' : $popover.find('.arrow').css('left', '180px');break;
default : break;
}
})
To get this to work, there must be only one popover shown at a time (see fiddle). It can be worked out with multiple visible popovers also, but then we need to add some HTML to the popover content.
see demo -> http://jsfiddle.net/uteatyyz/
As what I have understood so far, you want to achieve the popover to the left of the button.
Please check this Plunker Link
HTML Code:
<div class="pull-right">
<button type="button" mypopover data-placement="left" title="title">Click here</button>
</div>
Angular Code:
var options = {
content: popOverContent,
placement: "bottom",
html: true,
date: scope.date,
trigger: 'focus'
};
I have edited the answer as per the images that you have shown.
If this is not is answer, then please comment below.
Regards D.

Bootstrap modal at top of iframe regardless of scroll position. How do I position it on screen?

When embedding a Bootstrap app in an iframe, modal dialogs always open at the top of the iframe, not the top of the screen. As an example, go to http://getbootstrap.com/javascript/ and open an example modal on the page. Then using the sample code below which places the same bootstrap page in an iframe, find a modal and open it:
<html>
<head>
</head>
<body>
<table width="100%">
<tr><td colspan="2" style="height:80px;background-color:red;vertical-align:top">Here's some header content I don't control</td></tr>
<tr><td style="width:230px;height:10080px;background-color:red;vertical-align:top">Here's some sidebar content I don't control either</td>
<td valign="top">
<iframe width="100%" height="10000px"
scrolling="no" src="http://getbootstrap.com/javascript/">
</iframe>
</td>
</tr>
</table>
</body>
</html>
Demo in fiddle
How do I go about positioning the modal on the screen in this scenario?
UPDATE: Unfortunately, my iFrame cannot fill the screen, nor can I make it fixed since it needs to blend into the rest of the page and the page itself has enough content to scroll. This is not my design and I ultimately intend to rework the whole thing, but this is what I have to work around for now. As a temporary option, I'm using javascript to tell the iframe parent to scroll to the top where the modal dialog pops up. While this is acceptable, this isn't the desired behavior.
I'm using angularjs and the ui-bootstrap library in my code but as you can see above, it's a bootstrap issue.
If your iframe has the same document.domain as the parent window or it is a sub domain, you can use the code below inside the iframe:
$('#myModal').on('show.bs.modal', function (e) {
if (window.top.document.querySelector('iframe')) {
$('#myModal').css('top', window.top.scrollY); //set modal position
}
});
show.bs.modal will fire after you call $('#myModal').show()
window.top.scrollY will get the scrollY position from the parent window
In case your document.domain differs from the parent, you can hack it getting the onmousedown position inside the iframe. For example:
$('#htmlElement').on('mousedown', function (event) {
event.preventDefault();
$('#myModal').data('y', event.pageY); // store the mouseY position
$('#myModal').modal('show');
});
$('#myModal').on('show.bs.modal', function (e) {
var y = $('#myModal').data('y'); // gets the mouseY position
$('#myModal').css('top', y);
});
Quite old question but I don't see the solution/workaround I've found. It might be helpful for someone in the future.
I had the same issue - my iFrame doesn't fill the entire screen, it displays bootstrap's modal and it is loading content from different domain than the parent page.
TL;DR
Use window.postMessage() API - Documentation here. for communication between parent and iframe (cross-domain)
pass message with currentScrollPosition and Y position of your iframe
Reveive message and update modal's padding from the top
In my case the workaround was to use window.postMessage() API - Documentation here.
It requires to add some extra code to the parent and handle message in an iFrame.
You can add EventListener and listen to 'scroll' event. Each time the event handling function is invoked you can get currentScrollPosition like document.scrollingElement.scrollTop.
Keep in mind that your iframe can have some margin from the top in the parent page so you should also get its 'offset'.
After that you can post these two values to your iframe e.g. ncp_iframe.contentWindow.postMessage(message, '*');
Note that the message has to be a String value
After that in your iFrame you need to add EventListener and listen to 'message' event.
The event handling function will pass your 'message' in event.data property. Having that you can update modal padding. (Looks much better if you don't use animations e.g. fade, in classes);
Quick Example:
Parent:
window.addEventListener('scroll', function(event){
var myIframe = document.querySelector('#myIframe');
var topOffset = myIframe.getBoundingClientRect().top + window.scrollY;
var currentScroll = document.scrollingElement.scrollTop;
myIframe.contentWindow.postMessage(topOffset + ':' + currentScroll, '*');
});
iFrame:
window.addEventListener('message', function(event) {
var messageContent = event.data.split(':');
var topOffset = messageContent[0];
var currentScroll = messageContent[1];
//calculate padding value and update the modal top-padding
}, false);
This is a bug in most browsers (IE appears fine) where the elements are fixed to the iframe, not the window. Typically, if you need something to be relative to the main document, it has to be in the main document.
A workaround is to wrap your iframe in a fixed position div that takes up the whole width of the screen and then maximize the iframe within that. This appears to resolve the issue
HTML:
<div class="fixframe">
<iframe src="http://getbootstrap.com/javascript/"></iframe>
</div>
CSS:
.fixframe {
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
}
.fixframe iframe {
height: 100%;
width: 100%;
}
Working Demo in fiddle
See Also:
position:fixed inside of an iframe
iframe with a css fixed position : possible?
position fixed div in iframe not working
It is because the class .modal has position: fixed attribute. Try position: relative instead.

Add horizontal scroll to asp.net listbox control

How can I add horizontal scroll capabilities to the asp.net listbox control?
Example to add horizontal scroll:
<asp:ListBox ID="List" runat="server" Height="320px" Width="100%" style="overflow-x:auto;"SelectionMode="Multiple">
</asp:ListBox>
CSS3 overflow-x Property: http://www.w3schools.com/cssref/css3_pr_overflow-x.asp
We can put this list box inside a DIV and set the style for DIV to overflow which will automatically show the scroll bar whenever necessary.
Your aspx page has the following DIV:
<div id='hello' style="Z-INDEX: 102; LEFT: 13px; OVERFLOW:
auto; WIDTH: 247px; POSITION: absolute; TOP: 62px; HEIGHT: 134px" >
Put your asp:listbox inside the DIV definition. In page_load function, you need to define the width and height of the list box properly, so that it won't overflow with the DIV.
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
int nItem = Convert.ToInt32(ListBox1.Items.Count * 17);
ListBox1.Height = nItem;
ListBox1.Width = 800;
}
}
Code and solution available at http://www.codeproject.com/KB/custom-controls/HorizontalListBox.aspx
If you really, really need it, one idea would be to create a custom
ListBox class whose HTML looks like this: sets the width of the SELECT
to that of your widest value's width (the max width of the scrollbar,
for example). Now wrap that SELECT inside of a DIV of the 'constrained'
size and let it scroll on overflow.
Here's a quick example starting down those lines, here's the type of
HTML you want spit out by a control:
<div style="width:200px; height:100px; overflow:auto;">
<SELECT size="4">
<OPTION
Value="1">blahblahblahblahblahblahblahblahblahblah blahblah</OPTION>
<OPTION Value="2">2</OPTION>
<OPTION Value="3">3</OPTION>
<OPTION Value="4">4</OPTION>
</SELECT>
</div>
so in essence I'd recommend creating a composite custom control for
this, which renders this HTML. They're pretty easy to make, Google on
the terms 'composite control asp.net'.
The toughest part will be matching up the div dimensions to that of the
select box, to make the scrollbars work/line up properly. That's why
it's kinda tricky.
Source
Also, take a look at this: Automatically Adding/Hide Horizontal Scroll bar in the ListBox control
EDIT: Make sure you have enough height to include the scroll bar height or else you'll get the vertical scroll bar on both controls.
If you are doing it only for display purpose, You can do it in another way by using Textbox with mulitiline property. By appending the text with new line as such!
List<Yourclass> result = null;
result = Objname.getResult(Parameter1, Parameter2);
foreach (Yourclass res in result)
{
txtBoxUser.Text += res.Fieldname1.ToString();
txtBoxUser.Text += "\r\n" + res.Fieldname2.ToString();
txtBoxUser.Text += "\n\n";
}
Hence you will get the view of mulitline textbox with All your data arranged in good format as above code(New line and all). And also it will wrap your texts if it exceeded the width of your textbox. Also you no need to bother about the scrollsbars and here you will get only vertical scroll bar since all our results have been wrapped as per the behaviour of textbox.

Resources