What is the difference between Ext.Components' isVisible() and isHidden() method? - extjs

In ExtJS document, https://docs.sencha.com/extjs/6.5.3/classic/Ext.Component.html,
There is no clear description of both the methods

To answer this question you need to analyze the source code. Here is the method isHidden:
...
isHidden: function() {
return this.hidden;
},
...
And here is the method isVisible
...
isVisible: function(deep) {
var me = this,
hidden;
if (me.hidden || !me.rendered || me.destroyed) {
hidden = true;
} else if (deep) {
hidden = me.isHierarchicallyHidden();
}
return !hidden;
},
...
Besides hidden, isVisible checks whether this component is already rendered, and whether it is in the process of destruction.
Also when isVisible calling with parameter deep, it can check if the element is displayed, for example, in the collapsed panel

Related

React list, how does if else exactly work?

so in my React App, I basically have three buttons. When the specific button is clicked, I want to update the clicked value to be true. I also want the rest of the items that weren't clicked to be false. Is there another way to target the elements that weren't clicked on? I got this solution, but am confused on how it exactly works. I thought that if the first if statement returned true, the else if wouldn't run? So can someone explain how these are both running?
class App extends React.Component {
// state
state = {
list: this.props.tabs,
currentTabContent: '',
};
// event handlers
onButtonClick(tab) {
// ======THIS IS WHAT I DON'T UNDERSTAND========
const newList = this.state.list.map((item) => {
if (item === tab) {
item.clicked = true;
} else if (item !== tab) {
item.clicked = false;
}
return item;
});
// ==============================================
this.setState({
currentTabContent: tab.content,
list: newList,
});
}
// helpers
renderButtons() {
return this.props.tabs.map((tab, index) => (
<li key={index}>
<button
className={tab.clicked ? 'offset' : null}
onClick={() => this.onButtonClick(tab)}
>
{tab.name}
</button>
</li>
));
}
renderContent() {
return this.state.currentTabContent;
}
render() {
return (
<div className="App">
<ul>{this.renderButtons()}</ul>
<div className="display">{this.renderContent()}</div>
</div>
);
}
}
export default App;
I think your misunderstanding lies more in not quite understanding if...else if rather than anything to do with React. Let's take a look at your condition:
if (item === tab) {
item.clicked = true;
} else if (item !== tab) {
item.clicked = false;
}
return item;
This function runs when the following is called by the button's click handler:
() => this.onButtonClick(tab)
Where tab is a specific object corresponding to a specific button. You then map over list in state, which just appears to be the same list of tabs. For each object it checks if tab === listItem if that is true the stuff in the first block executes, that's why the correct button gets set to true. It then does not evaluate the second condition for that item, and just returns the item.
It then moves on to the other items, who will not be equal to tab, and they evaluate in the second condition, so they are marked as false for clicked.
There are some much more worrisome and larger issues in your code here that have more to do with you making comparisons between objects and the dataflow of your components, but those aren't the subject of your question here, I just wanted to warn you to look out for them in the future.

How to check dynamically rendered checkboxes

I'm rendering some checkboxes dynamically, but currently I'm only able to check the first box, and all other boxes operate the first one. How do I get the boxes to work independently of each other?
This is typescript in React. I've tried changing the interface I'm referencing in the function, thinking I was referencing the wrong thing, but none of those worked.
This is the function:
handleCheckboxClick = (entitlement: IApiEntitlements, checked: boolean): void => {
if (checked === true) {
this.selectedEntitlementIDs.push(entitlement.id);
} else {
const index: number = this.selectedEntitlementIDs.indexOf(entitlement.id);
this.selectedEntitlementIDs.splice(index, 1);
}
//tslint:disable-next-line:prefer-const
let entitlementChecked: IEntitlementChecked = this.state.entitlementChecked;
entitlementChecked[entitlement.id] = checked;
let selectAll: boolean = false;
if (this.selectedEntitlementIDs.length === this.state.responses.apiResponses.apiClients.length) {
selectAll = true;
}
this.setState({
entitlementChecked: entitlementChecked,
selectAll: selectAll
});
console.log(this.selectedEntitlementIDs, 'hi');
console.log(entitlementChecked, 'hello');
}
And this is where it's being called:
return (
<Checkbox
checked={this.state.entitlementChecked[entitlement.id]}
data-ci-key={entitlement.id}
id='api-checkbox'
key={entitlement.id}
labelText={entitlement.label}
onChange={this.handleCheckboxClick}>
</Checkbox>
);
I expect each checkbox to be able to be checked, but currently on the first one works, and all others check or uncheck that first one.
You shouldn't keep an array as a property on the class that keeps track of selected items, this isn't tied to the React lifecycle and could potentially not update the view when you want to. Instead you should just use your map (entitlementChecked) you already have to determine if something is checked or not.
handleCheckboxClick(id) {
this.setState(prevState => ({
entitlementChecked: {
...prevState.entitlementChecked,
[id]: !prevState.entitlementChecked[id]
}
}));
}
When calling the handler method, you can just pass the id through that you need specifically.
onChange={this.handleCheckboxClick.bind(null, item.id)}
Here's a rudimentary example for more detail :)

Intercept checkbox change event in VueJS

I have a long set of checkboxes. I would like two groups of three of them to behave as radio buttons. Now, leaving aside my UX choices, how can I make this work?
The checkboxes are implemented as properties on a single object, layer:
data() {
return {
layer: {},
}
},
watch: {
layer: {
handler(val, oldval) {
mapping.updateLayers(val)
},
deep: true,
},
},
That works fine. But intercepting val and updating this.layer inside handler() doesn't:
handler: function(val, oldval) {
if (val.FutureYear) { this.layer.NextYear = false; this.layer.ExistingYear = false; }
if (val.ExistingYear) { this.layer.NextYear = false; this.layer.FutureYear = false; }
if (val.NextYear) { this.layer.ExistingYear = false; this.layer.FutureYear = false; }
mapping.updateFoiLayers(val);
},
How can I achieve this result? (I'd prefer not to have to implement actual radio buttons because that makes managing all the layers and UI more complex.)
Example: https://codepen.io/jacobgoh101/pen/NyRJLW?editors=0010
The main problem is the logic in watch.
If FutureYear is selected already, other field becomes unchangeable. Because if (val.FutureYear) is always the first one being triggered and the other 2 field will always be set to false immediately.
Another thing about watch is that it will be triggered when
user changed the value
program changed the value (this is unnecessary and make things harder to handle)
Therefore, handling #change event is more appropriate in this scenario.
JS
methods: {
handleChange: function(e) {
const name = e.target.name;
if (this.layer[name]) {
Object.keys(this.layer).map((key)=>{
if(key != name) {
this.layer[key] = false;
}
})
}
}
}
html
<div id="app">
<input type="checkbox"/ v-model="layer.FutureYear" name="FutureYear" #change="handleChange($event)">FutureYear<br/>
<input type="checkbox"/ v-model="layer.NextYear" name="NextYear" #change="handleChange($event)">NextYear<br/>
<input type="checkbox"/ v-model="layer.ExistingYear" name="ExistingYear" #change="handleChange($event)">ExistingYear<br/>
</div>

setState not updating when set to boolean

I have the following method in a react component:
handleCheckBoxClick() {
var checkbox = document.getElementById("boldCheckbox").checked;
this.setState({ischecked : checkbox});
if(this.state.ischecked) {
this.setState({weight:'bold'});
} else {
this.setState({weight:'normal'});
}
}
but if I change the if statement to:
if(checkbox) {
this.setState({weight:'bold'});
} else {
this.setState({weight:'normal'});
}
it works fine but I can't figure out why the first way doesn't work.
The method setState() is asynchronous, and updates are often batched together. In your case, ischecked is updated together with the weight, so when you set the weight you still refer to the old value.
One solution is to use setState()'s callback that will be called after the state is updated.
Note: to get the checkbox checked state, use the event object e passed to the handler instead of querying the DOM.
handleCheckBoxClick(e){
var checked = e.target.checked;
this.setState({ischecked : checked}, function() {
if(this.state.ischecked){
this.setState({weight:'bold'});
}else{
this.setState({weight:'normal'});
}
});
}
A better solution is to update both properties because you know if the checkbox is checked:
handleCheckBoxClick(e){
var checked = e.target.checked;
this.setState({
ischecked : checked,
weight: checked ? 'bold' : 'normal'
});
}
Thats cause this.setState({ isChecked : checkbox }); has not finished before you ask it in the if statement.

CheckAll/UncheckAll issue with Subscribe ? Knockout

I been trying to do checkbox Checkall and UnCheckall using subscribe and i'm partially successful doing that but i am unable to find a fix in couple of scenarios when i am dealing with subscribe .
Using subscribe :
I am here able to checkAll uncheckAll but when i uncheck a child checkbox i.e test1 or test2 i need my parent checkbox name also to be unchecked and in next turn if i check test1 the parent checkbox should be checked i.e keeping condition both child checkboxes are checked .
For fiddle : Click Here
ViewModel :
self.selectedAllBox.subscribe(function (newValue) {
if (newValue == true) {
ko.utils.arrayForEach(self.People(), function (item) {
item.sel(true);
});
} else {
ko.utils.arrayForEach(self.People(), function (item) {
item.sel(false);
});
}
});
The same scenario can be done perfectly in easy way using computed but due some performance issues i need to use subscribe which is best way it wont fire like computed onload .
Reference : Using computed same thing is done perfectly check this Fiddle
I tried to use change event in individual checkbox binding but its a dead end till now.
Any help is appreciated .
Your subscription only applies to edits on the selectedAllBox. To do what you want, you'll need subscriptions on every Person checkbox as well, to check for the right conditions and uncheck the selectedAllBox in the right situations there.
It strikes me as odd that this would be acceptable but using computed() is not. Maybe you should reconsider that part of your answer. I would much rather compute a "isAllSelected" value based on my viewModel state, then bind the selectedAllBox to that.
I solved a similar problem in my own application a couple of years ago using manual subscriptions. Although the computed observable method is concise and easy to understand, it suffers from poor performance when there's a large number of items. Hopefully the code below speaks for itself:
function unsetCount(array, propName) {
// When an item is added to the array, set up a manual subscription
function addItem(item) {
var previousValue = !!item[propName]();
item[propName]._unsetSubscription = item[propName].subscribe(function (latestValue) {
latestValue = !!latestValue;
if (latestValue !== previousValue) {
previousValue = latestValue;
unsetCount(unsetCount() + (latestValue ? -1 : 1));
}
});
return previousValue;
}
// When an item is removed from the array, dispose the subscription
function removeItem(item) {
item[propName]._unsetSubscription.dispose();
return !!item[propName]();
}
// Initialize
var tempUnsetCount = 0;
ko.utils.arrayForEach(array(), function (item) {
if (!addItem(item)) {
tempUnsetCount++;
}
});
var unsetCount = ko.observable(tempUnsetCount);
// Subscribe to array changes
array.subscribe(function (changes) {
var tempUnsetCount = unsetCount();
ko.utils.arrayForEach(changes, function (change) {
if (change.moved === undefined) {
if (change.status === 'added') {
if (!addItem(change.value))
tempUnsetCount++;
} else {
if (!removeItem(change.value))
tempUnsetCount--;
}
}
});
unsetCount(tempUnsetCount);
}, null, 'arrayChange');
return unsetCount;
}
You'll still use a computed observable in your viewmodel for the the select-all value, but now it'll only need to check the unselected count:
self.unselectedPeopleCount = unsetCount(self.People, 'Selected');
self.SelectAll = ko.pureComputed({
read: function() {
return self.People().length && self.unselectedPeopleCount() === 0;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(value);
});
}
}).extend({rateLimit:0});
Example: http://jsfiddle.net/mbest/dwnv81j0/
The computed approach is the right way to do this. You can improve some performance issues by using pureComputed and by using rateLimit. Both require more recent versions of Knockout than the 2.2.1 used in your example (3.2 and 3.1, respectively).
self.SelectAll = ko.pureComputed({
read: function() {
var item = ko.utils.arrayFirst(self.People(), function(item) {
return !item.Selected();
});
return item == null;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(value);
});
}
}).extend({rateLimit:1});
http://jsfiddle.net/mbest/AneL9/98/

Resources