Is it possible to show primeng tooltip conditionally? - primeng

I'm using primeng tooltip, and I need to show the tooltip only when the input is invalid. I'm using following code but the tool tip is displayed on hover or on focus.
I have tried using tooltipDisabled and tooltipEvent.
<input type="url" name="url" class="form-control" pattern="(https|http)?://.+"
formControlName="url" [disabled]="flag2" pTooltip="Please enter URL in valid format"
tooltipPosition="left" tooltipEvent="focus">
Expected: Tooltip should be displayed only if input box is invalid
Actual: tooltip is displayed on hover or focus

So the short answer is: no, you can't.
The long answer is: you can show it programatically, but it will also still display through the only options made available by primeNg - onHover and/or onFocus - unless you remove those interactions from the element.
Displaying Tooltip programatically
What you can try and do is force the event that triggers the tooltip on the element on which you have it attached to. There are several ways that can be used to find an element, and that is not your question, but you can find your url input field for example by looking for it on the DOM through its name.
var element = document.getElementsByName("url")[0];
After whichever validation you have fails, you can use that variable to dispatch the event that triggers the tooltip.
element.dispatchEvent(new Event('mouseenter'));
When the element is valid you can make the tooltip disappear by also dispatching the appropriate event.
element.dispatchEvent(new Event('mouseleave'));
As I said above, this will not prevent it from appearing when you hover or focus your input, but it answers your question of how it can be done.
Workaround to prevent standard behaviour
In order to not have the tooltip appear whenever the Element is hovered or focused, I suggest that you actually attach it to another element alltogether. One that you can create and connect right next to your input field, or in it. The important thing is that it is not the field itself that you want to interact with. And then you can use CSS and add to the element with the tooltip no mouse events, for example through a class.
.noPointerEvents {
pointer-events: none;
}
This will ensure that the user won't activate the tooltip with the mouse. And it will only trigger through the previousl given code. You can also disable tabbing, if you selected one element that can be tabbed through.

There is a hack. But it is a hack and I would not recommend this. Since primeng doesn't expose any way to control the tooltip you have to do it by accessing the element manually. Following is one way to do this.
Add two classes to the tooltip using tooltipStyleClass, one class d-none which has display:none !important; property and other class random-class to access the element using jquery or javascript. Using jQuery we will access the element and remove class d-none when the input is invalid. This check has to be implemented in (focus) = 'onFocus()' function.
In the onFocus function remove the d-none class from the tooltip element if the input field is invalid. If the input field is valid then add the d-none class to the element
HTML
<input type="text" pInputText pTooltip="Enter your username" placeholder="Right" tooltipStyleClass="d-none random-class" tooltipEvent="focus" (focus)="onFocus()">
CSS
.d-none {
display: none !important;
}
Javascript/Component
onFocus() {
if (//input field invalid) {
setTimeout(() => {
$('.random-class').removeClass('d-none');
}, 100);
}
}
I cannot stress enough on the fact that this is a hack, I do not recommend this but it gets the job done. If you want to replicate this on other input fields then every field should have different random class name to access that specific element.

Related

Editing feature for react

I am implementing edit feature with react now. The problem is that I haven't found the good solution for this yet.
I want to make a view like below.
Both title and description text area are already written with default text.
This text is not placeholder.
If user click the button, User can edit the text.
I tried the below two packages but it is not perfect for my purpose.
TextareaAutosize
import TextareaAutosize from 'react-autosize-textarea';
TextareaAutosize has a value attribute. but if I use this, I can't edit the text in it. And the defaultValue seems not working.
Do you know how to put a default text value into TextareaAutosize component?
2.AvInput
import { AvForm, AvField, AvGroup, AvInput, AvRadioGroup, AvRadio } from 'availity-reactstrap-validation';
I think this is another good solution but the submit button seems not to be customized.
I should place the Edit button in the right-upper side of view.
But if I use this package, The submit button is placed at the bottom and it seems like it should be used tag.
Do you know how to connect my own submit button with AvInput?
The button is in other tags, not in its .
https://availity.github.io/availity-reactstrap-validation/components/avform/
<FormGroup>
<Button>Submit</Button>
</FormGroup>
other solution
If you have a better solution or experience, plz let me know.
Thank you in advance
I referred to the below answer and changed UX.
Submit form using a button outside the <form> tag
The elements used to create controls generally appear inside a FORM element, but may also appear outside of a FORM element declaration when they are used to build user interfaces. This is discussed in the section on intrinsic events. Note that controls outside a form cannot be successful controls.
submit button seems to be included in the form tag.

Ng dirty not showing after save button clicked

My application so far is working great. It is not a form (no form tagged used) but it is a series of input boxes that a user must enter. Each input box that a user fills, I am adding an orange border on that input field. I am doing that through:
app.css:
#modifyTop .ng-dirty{
border: 2px orange;
}
index.html:
...
<body id="modifyTop" name="modifyTop" ng-controller="ModifyPageCtrl">
<button ng-click=save()>Save</button>
....
Inside this index.html is a save button. Once I hit the save button, the border field goes away. I am doing this through (I used jQuery inside an Angular controller, not sure if thats acceptable):
ModifyPageCtrl.js:
....
function save(){
....
$('#modifyTop .ng-dirty').removeClass('ng-dirty')
...
}
So the problem is the following. After hitting save, if say the user wants to change again a particular input field, then it does not make that orange border show up. Only the fields that were previously untouched/not modified have the border appear. I have to reload the page, to make the border appear again in those particular input fields. Can someone please provide examples on how I can make this work? I understand I have given very small snippets of my code thats because my work doesn't allow me to paste company code but I will try to provide more details if people are unable to help with the provided information. Also, would like to mention that my app has no errors- this is a enhancement fix that i am working on.
Thank you
You need to use $setPristine():
http://docs.angularjs.org/api/ng/type/form.FormController
From the docs:
Sets the form to its pristine state.
This method sets the form's $pristine state to true, the $dirty state
to false, removes the ng-dirty class and adds the ng-pristine class.
Additionally, it sets the $submitted state to false.
This method will also propagate to all the controls contained in this
form.

How to show autocomplete drop-down when first clicking in text box?

I am using a Angular md-autocomplete which starts showing users the auto completion options in a drop-down after they first type in the text box. Is there anyway to have this dropdown shown when the user first clicks in the text box as well?
Here is the md-autocomplete html:
<md-autocomplete flex
role="combobox"
md-selected-item="text"
md-no-cache="true"
md-search-text="searchText"
md-search-text-change="searchTextChange(searchText)"
md-items="item in getMatches(searchText)"
md-item-text="item.autocompleteVal"
md-min-length="0"
md-selected-item-change="$parent.selectedItemChange(item)" on-enter ng-cloak>
<span id="autocompleteText" md-highlight-text="searchText" md-highlight-flags="^i">{{item.autocompleteVal}} </span>
</md-autocomplete>
I was having same issue but setting the value of md-min-length to zero starts working
md-min-length="0"
Update:
If it still does not work then make sure that the searchTerm is initially set to null
Controller
vm.searchTerm = null
Html:
md-search-text="vm.searchTerm"
As #Hodglem pointed out, the current Material docs use the valueChanges observable of the FormControl object to detect changes and filter the options to display on the autocomplete panel. They prime the initial value as "null" so that all the available options will display.
However, often your list of options comes from a service (as in my use case) and your list is empty when startsWith(null) runs, especially if this code is in the ngOnInit() method like it is in the Material docs. This method runs immediately, while the service takes time to fill the list.
Autocomplete is smart enough to not open the panel if there are no options, so the initial focus on the element will not open the panel since there are no options to display. Even after the list fills from the service, the filter only gets triggered with a change in value on the control, so until the user starts typing, autocomplete's list of options remains empty, and therefore the panel remains closed.
I have two solutions:
Move the observable set up out of the ngOnInit() method, and into the subscribe() method that follows the call to the service that retrieves the options. After setting the list, run the observable set up. Now the panel will open on focus since the panel has options to display. (Make sure that the initialization of the FormControl remains in the ngOnInit() method, or the binding in the template will throw an error.)
Scratch the observable approach, and bind the filter method to the control's native events, such as (focus) and (input). In the filter method, check if the passed-in value is null or empty, and if it is, return the entire list. This way, the filter gets triggered every time the user clicks on the control or changes its value, and as long as the user clicks on the control at least once after the service filled the list of options, the panel will display. Depending on your use case, I found that by the time the user moves the mouse and focuses on the control, the service already delivered the goods, and the panel opens.
Seems like demo from site works as you expected.
https://material.angularjs.org/latest/demo/autocomplete
For Angular 2 and Material 2, setting startWith() on the valueChanges() observable of the control to null will show all of the values. Omitting this will result in the user first needing to type a value in to see results.
All values displayed on focus:
this.filterFuelTypeObservers.push(newFormGroup.controls.fuelType.valueChanges
.startWith(null)
.map(value => value ? this.fuelTypeFilter(value) : this.fuelTypes));
No values displayed until entry:
this.filterFuelTypeObservers.push(newFormGroup.controls.fuelType.valueChanges
.map(value => value ? this.fuelTypeFilter(value) : this.fuelTypes));
I haven't, but I imagine you could play around with startWith() to set the on focus list to be filtered by something also.
Just add the following line
md-min-length="0"
This will trigger a md-items calls even when just clicked

Trigger click event of another element in angular?

I have an input box and Its bound with datepicker. In my view, there is small calendar icon besides this input box. I want to trigger click event of an input box when user clicks on this calendar icon. I have done this using directive which I have applied to calendar icon. But its almost like jQuery. So is there any different way to achieve this? If my approach is wrong then please guide me to the right direction. I am new to angular and I have read some articles where I read that avoid use of jQuery. Thanks
My Directive
myApp.directive('openCal',function($compile,$filter) {
return {
link:function(scope,element,attrs) {
element.bind("click",function() {
element.siblings("input").trigger("click");
});
}
};
});
Its working fine. But I am not sure that is it right approach or not??
No, if I understand what you are trying to do you are over-complicating things a bit.
In your case it looks like you would have something like:
<img open-cal/>
<input ng-click="doSomething()">
Where click on the img triggers a click on the input, via the openCal directive. Instead considering doing something like this:
<div ng-click="doSomething()">
<img>
<input>
</div>
If doSomething() needs to get data from the input, use ng-model to bind data from your input to your scope.
ALTHOUGH!
If you ever need to do a directive, that is the right way to do it. Using element.bind is not a problem since that is included in Angular. What you want to avoid is using stuff like $('.calendar').click and such.
Another way to approach this would be to add a <label> element for your input field that contains the calendar. Then clicking the calendar would focus the input field. Then all you'd have to do is listen for the focus event on your input field to do your extra work. This has the added bonus of working if someone navigates to your input field via the keyboard by hitting the tab key.

How to format combo in extjs?

I have a combo box in ext js , which is dynamically populated. Nothing very complex...and it populates correctly. This is the structure of the display values of the combo:
Name: [dynamicName]
Gender : [dynamicGender]
Age: [dynamicAge]
The objective is to have the Name:, Gender: and Age: inside <b></b> tag. The dynamic values should be in normal text.
Let's say I define an array from which i will populate the datastore of the combo. This is the array:
var arr=[[id1, <b>Name:</b>],[id2, <b>Gender:</b>],[id3, <b>Age:</b>]]
The thing is when i click the dropdown, in the list, they show up proper. As soon as the user selects an option, let's say Name...in the selected option, the formatting goes all wrong. By wrong I mean, the bolded text is not shown. Instead , the string literal <b>Name:</b> dynamicName is showed.
How can i use tpl syntax to solve this?
You can solve this with css. Here is one way:
In the config for the combo box, add:
itemCls: 'make-bold'
(or name this class whatever you want)
Then, in a style sheet, add (using the same name):
.make-bold input {
font-weight: bold;
}
This will style your input box (what's displayed after you've selected from the combo box) in bold.
While the option list is made of <div> elements, thus allowing for styling, the field itself is just an <input> element, and these do not support content styling.
So the answer is: no, you can't.
The extended answer is: I'm pretty sure someone did an alternate implementation of combobox component, that uses different HTML markup and allows for styled content in the field. Try asking on ExtJS forums.
I had a similar issue. I want to have a few selections in the combo list bold, but I don't want the HTML markup in the input when the value is selected:
1. Use a Template as this tutorial explains, see Using templates to change the look of combo box items.
Or
2.Use a Select Listner and Regex. You can put a listener on the "select" event and then simply use some regex to strip HTML tags like /<[^>]*>/g to remove HTML tags from input field. Now your HTML used to format the list won't affect the input.

Resources