I have created a table with checkbox components (ng prime components). Does anyone know how I can control the event without changing the value? I have used the Onchange () function
but was done before changing it so if my condition is successful the value is changed.
<p-checkbox [(ngModel)]="rowData[col.field]" binary="true" (onChange)="btnComprobarMismoTipo($event, rowData.etiqueta, rowData.tipo)" (change)="btnPrueba()"></p-checkbox>
Use
[ngModel]="rowData[col.field]"
instead of 2-ways binding
[(ngModel)]="rowData[col.field]"
Handle logic in onChange event, then change rowData[col.field] value if valid condition
Related
I am using watch,setValue and getValues to update one dropdown selected value based on another dropdown selected value.
It can be also done using dropdown list's onChange so, onChange, setValue and getValues so no need to use of watch.
Can you please guide, watch is performance cost then using onChange or it will be fine with watch how its implemented below (without onChange).
const dropdownList_1_watch_value = watch(dropdownList_1);
useEffect(()=>{
if (dropdownList_1_watch_value !== 'specificValue') && getValues(dropdownListControlName) !== defaultValue)
{
setValue(another_dropdownListControlName, defaultValue);
}},[dropdownList_1_watch_value]);
return (
<>
// list of dropdown list components and other controls
</>
);
Regarding performance there shouldn't be much of a difference between those to.
I will cite from a blog post:
React Watcher should be used sparingly, in cases where you can't
really solve the problem any other way. In most cases, where you need
to do something when some prop changes, you don't really need it. Why?
Because in most cases you can usually trigger the event together with
the action with caused the prop to be changed, e.g. when triggering a
filtering change on a listing.
Full post: http://sborrazas.com/blog/react-watcher
I'm using the React Switch component straight from this website: http://react-materialize.github.io/react-materialize/?path=/story/components-switch--switch. I put this into my SideNav like so:
<Switch
id="Switch-11"
offLabel="Off"
onChange={(e) => exampleFunction(e)}
onLabel="On"
/>
I did it so that when the switch is clicked, it would call "exampleFunction()" which contains this:
const exampleFunction = (e) => {
console.log(e.target.value)
}
The problem is that when I look at the console for the value of the switch, it is always "on," even if I press it multiple times. I'm a little lost as to why this happens. Any advice would be appreciated. Thanks.
If you want to know whether the checkbox is checked, you need to use e.target.checked, looking at the source code from materialize, we can see the onChange is passed directly to the input element, so you need to use the checked attribute of the input element.
The value attribute has the following definition:
The value property sets or returns the value of the value attribute of a checkbox.
For checkboxes, the contents of the value property do not appear in the user interface. The value property only has meaning when submitting a form. If a checkbox is in checked state when the form is submitted, the name of the checkbox is sent along with the value of the value property (if the checkbox is not checked, no information is sent).
From: https://www.w3schools.com/jsref/prop_checkbox_value.asp
Goal:
It's about the Material Autocomplete from material-ui for React in variant freeSolo. I understand that one is asked to handle value and inputValue independently, but because Formik and Yup are used to save the state and apply validation I would prefer to have only one value outside. For splitting this increases complexity in the outer code noticeably.
Attempt:
https://codesandbox.io/s/autocomplete-with-a-single-state-v442c?file=/demo.tsx
Is an example where I set the prop inputValue to value.title || '' and in onInputChange I check if the inputValue matches an existing option and otherwise create a new object, both to mimic onChange.
Issue:
Unfortunately, the list does not become filtered anymore. I had added some logging in my attempt was everything worked as expected and I can't infer what issue the component runs into. I hope anyone has some idea or ideally working code? So again, my overall goal is to have only one value representing the state and that, therefore, needs to be an object.
So I realised this can not be done because the states value and inputValue update at different times. value is only affected by inputValue once the user clears the input completely, setting inputValue to '' and value becoming null. So the asynchronous nature does not allow storing it in a single value in a clean way.
I have React code like this:
handleTransitionEnd() {
console.log('ended');
}
<div onTransitionEnd={(ev) => this.handleTransitionEnd(ev)}....
The peculiar thing is that my logs are filling up with ended. Even if I don't have any transition css logic tied to the element at all. It seems to be firing on every state change or re render. Is this normal? I would expect it to only fire when a css transition ends.
Is there some other way this callback should be achieved?
Thanks
UPDATE:
here is a sandbox showing some strangeness: https://codesandbox.io/s/vy5wwyq5v3
Clicking the first button causes the callback to be called 3 times, then if you click the second button it gets called another 2 times even tho a transition doesn't happen. My app is even more extreme than this with it getting called a lot more often.
The css transition being used transition: "all 3s" is causing transitions on multiple properties, not just margin-left.
In the example provided, outline-color and outline-width were transitioned as well. They were then transitioned again when clicking anywhere else (not just on the second button).
You can see this by checking the event:
onTransitionEnd={e => {
e.persist(); // see: https://reactjs.org/docs/events.html#event-pooling
console.log(e.propertyName);
}}
The css transition could be more specific: transition: "margin-left 3s" to avoid this.
Alternatively, test e.propertyName for the desired case.
To add on to what dabs said in his answer, the transitionend event bubbles. This means if any children of your element have transitions on them, they will trigger the transitionend event on themselves, then bubble up to their parent, triggering on each of them, including the current element that you have the listener on.
A simple way to check that you're only running your logic for the element your listener is on is to compare e.target and e.currentTarget like so:
onTransitionEnd={e => {
if ( e.target === e.currentTarget ) {
// your logic here
}}
e.target is the element that starts the event, which can be one of the children, for example, not just the element with the listener on it.
e.currentTarget however always points to the element that has the listener on it, regardless of if it initiated the event or not.
By comparing the two, you can check that you're only running logic when it's the element with the listener on it that initiated it.
I have an AngularJS custom component that essentially wraps around a Material Design mdSelect, but provides easy configuration of available, default, and current values via its bindings.
But the component functions as a general editing component in an mdDialog that can change its options based upon the thing being edited. Thus is a "Next" button to go to the next "thing" to be edited. When the button is pressed the custom component will have new available, default, and current values—something like this:
<foo-component default-value="dialog.getDefaultFoo()" current-foo="dialog.currentFoo">
</foo-component>
Note that the component, if a list of available values is not given (as in the example above), the component assumes a list of values with only one value, the "default-value" indicated.
So when a user selects "Next", the list of values in the mdSelect will change, because the value returned by dialog.getDefaultFoo(). The new selected value will be dialog.currentFoo.
But if dialog.currentFoo is null, I want the control to automatically select the indicated default value, or if no default is indicated, the first available value. That's easy enough when the component is created using $onInit. But once it is created, how do I know (inside the component) that the user has selected "Next" and the list of available values has changed?
In the code for the "Next" button, I call this.fooForm.$setPristine(). According to the documentation, the when this method is called the form controller will "propagate to all the controls contained in this form." So I considered having my custom control hook detect that $setPristine() is being called, so that it can automatically select a default value from the list if the new value is null. But how now I'm back in the same situation: how does my custom component detect that $setPristine() is being called on the form?
In essence, my custom component needs to detect when one of its bound values changes, and perform some custom update of other values under certain conditions. I know that I can use a getter/settter from outside the custom component, but how does the custom component detect that one of its bound values has changed?
To make matters more complicated, dialog.currentFoo is actually a function, which my component recognizes as a getter/setter function which will return/update the correct value based upon the state of the dialog. So I can't even detect that this value has changed, because the actual function never changes—only the value that it returns will change.
And it's actually even more complicated than that, because the mdSelect is only one piece of the object that gets sent to dialog.currentFoo; otherwise it isn't propagated outside the component.
Trying to summarize, I need to know in a custom component if the binding dialog.currentFoo, which is really a getter/setter method, would now return null so that the custom component could select a default value (also dynamic) based upon the current items (also dynamic) listed in the internal mdSelect. I would accept workarounds, such as detecting that $setPristine() has been called on the enclosing form. I would even accept a hack, such as forcing AngularJS to recreate the custom component when some external state changes.
This is tricky, because AngularJS is tricky, and because it's exceedingly hard to track information on custom AngularJS control/input components.
Above all the first thing that needs to be done is to make the custom component use the normal ngModel framework; trying to "fake" it using a two-way bound currentValue doesn't cut it for this complexity, and besides, ngModel is the "correct" AngularJS way to do it. To pull this off you'll need to use NgModelController. Finding out how to do this with a component is difficult in itself, although one page gave the magic formula. It goes something like this:
require: {
ngModelCtrl: "ngModel"
},
bindings: {
ngModel: "<"
//TODO add defaultValue or whatever other properties here
},
Then you don't access the two-way value directly; you use the NgModelController interface:
//get the current value
const foo = this.ngModelCtrl.$modelValue;
//set the current value
this.ngModelCtrl.$setViewValue(foo);
As best I can tell, if you add ng-model-options="{getterSetter:true}" to the component, the ngModelOptions will automatically get applied to your model, and getters/setters will be called automatically.
Now you are hooked into the whole ngModel framework, and use NgModelController to add/access validators and all sorts of advanced features.
Getting back to my needs, where I need to "reset the component" in certain conditions, I can patch into NgModelController#$setPristine(). The form controller recognizes my component is part of the ngModel framework, and calls $setPristine() when the form is reset to its pristine state.
this.$onInit = () => {
this.ngModelCtrl.$setPristine = () => {
myInternalValue1 = null;
myInternalValue2 = this.defaultValue;
};
this.ngModelCtrl.$setPristine(); //initialize default value
};
This explains the doubt I had about the form controller "propagat[ing $setPristine()] to all the controls contained in this form", which I mentioned in my original question. The secret is that the component must become part of the real ngModel system so that it can interact as AngularJS is expecting, as well as to gain access to important internal methods.