setState not running in nested function - reactjs

this.setState at the end of constructBoard doesn't appear to run when contructBoard is called. The function runs and works as intended other that setState not appearing to run. The callback function doesn't run either.
class Board extends Component {
state = {
layout: null
}
contructBoard = (boardSize) => {
let board = []
let boardStateLayout = {}
for (let row = 0; row < boardSize; row++) {
let temp = []
for (let column = 0; column < boardSize; column++) {
let style = null;
let key = row.toString() + column.toString()
//Top left corner
if (row === 0 && column === 0) {
style = "topLeft"
//Top right corner
} else if (row === 0 && column === boardSize - 1) {
style = "topRight"
//Bottom left corner
} else if (row === boardSize - 1 && column === 0) {
style = "bottomLeft"
//Bottom right corner
} else if (row === boardSize - 1 && column === boardSize - 1) {
style = "bottomRight"
//Top row
} else if (row === 0 && (column > 0 && column < boardSize - 1)) {
style = "topRow"
//First column
} else if (column === 0 && (row > 0 && row < boardSize - 1)) {
style = "firstColumn"
//Bottom Row
} else if (row === boardSize - 1 && (column > 0 && column < boardSize - 1)) {
style = "bottomRow"
//Last column
} else if (column === boardSize - 1 && (row > 0 && row < boardSize - 1)) {
style = "lastColumn"
} else {
style = "middle"
}
temp.push(<td key={key} onClick={this.handleSquareClick} className={style}></td>);
boardStateLayout[key] = {
showEl: false,
el: "x"
}
}
board.push(<tr key={"row" + row.toString()}>{temp}</tr>)
}
this.setState({layout: boardStateLayout}, () => console.log('set state'));
return <table className="board"><tbody>{board}</tbody></table>
}
board = this.contructBoard(3);
render() {
return (
<div className="boardContainer">
{this.board}
{/*<XorO layout={this.state.layout} />*/}
</div>
);
}
}

You're basically trying to call setState during the component's construction which React Docs discourage.
If you want to set an initial state like that you should add a constructor and assign the state directly.
Like this:
this.state = { layout: boardStateLayout }

Related

how do I format my response array in angular?

Need to format my array for chart purpose
myArr=[["6709"],["1949"],["87484"],["12760"],["13326"],["3356"],["98000"],["16949"],["29981"],["7879"],["117640"],["30727"],["122071"],["21325"],["210406"],["65824"],["2744807"],["56664"],["382719"],["134578"],["2440528"],["83819"],["1362744"],["450092"],["2461"],["336"],["166446"],["16363"]]
Below Formatted Array
formatArr= [["6709", "1949", "87484", "12760"], ["13326", "3356", "98000", "16949"], ["29981", "7879", "117640", "30727"], ["122071", "21325", "210406", "65824"], ["2744807", "56664", "382719", "134578"] ["2440528", "83819", "1362744", "450092"], ["2461", "336", "166446", "16363"]]
You could reduce it like this for example:
const formatArr: string[][] = myArr.reduce((prev, item, index) => {
if (index % 4 === 0) {
// every fourth item creates a new array with the current item:
prev.push(item);
} else {
// every other item pushes to the previously added item:
prev[prev.length - 1].push(item[0]);
}
return prev;
}, [] as string[][]);
myArr = [["6709"],["1949"],["87484"],["12760"],["13326"],["3356"],["98000"],["16949"],["29981"],["7879"],["117640"],["30727"],["122071"],["21325"],["210406"],["65824"],["2744807"],["56664"],["382719"],["134578"],["2440528"],["83819"],["1362744"],["450092"],["2461"],["336"],["166446"],["16363"]]
formatArr = []
function makeArray(params) {
let element = [];
for (let i = 0; i < myArr.length; i++) {
element.push(myArr[i][0])
if ((i + 1) % 4 == 0) {
formatArr.push(element);
element = [];
}
}
console.log(formatArr);
}
makeArray();
This is correct if myArr has 4n element, if not use this
function makeArray(params) {
let element = [];
for (let i = 0; i < myArr.length; i++) {
element.push(myArr[i][0])
if ((i + 1) % 4 == 0) {
formatArr.push(element);
element = [];
}
if (i == myArr.length - 1 && (i + 1) % 4 != 0) {
formatArr.push(element);
}
}
console.log(formatArr);
}

I cannot set while to work properly in for loops in ts

I want to get array of arrays with unique values, but at some point
while
gets missed or ignored (I presume because of the asynchronous nature of it). Can someone help with a adding a promise to this, or setting
async/await
structure or giving better advise how to check the arrays. I tried adding
async/await
but I get error and I am not sure where I can add a promise or use it. It is
getSeveralArrays() {
for (let index = 0; index < 50; index++) {
this.getValue();
}
}
getValue() {
this.i++;
this.array = [];
this.randomArray = [];
for (let index = 0; index < 4; index++) {
this.randomValue = this.getRandom();
if (this.array.length === 2) {
while ((this.array[0] === this.randomValue) || (this.array[1] === this.randomValue)) {
this.randomValue = this.getRandom();
}
this.array.push(this.randomValue);
} else if (this.array.length === 3) {
while ((this.array[0] === this.randomValue) || (this.array[1] === this.randomValue) || (this.array[2] === this.randomValue)) {
this.randomValue = this.getRandom();
}
this.array.push(this.randomValue);
} else {
this.array.push(this.randomValue);
}
console.log({...this.array});
this.randomArray.push({ind: this.i, val: this.array});
}
}
getRandom() {
const value = Math.floor(Math.random() * 4);
return value;
}
There is nothing asynchronous in all your code, so no need for async/await. Also, while is not asynchronous.
You were missing a case for the length of 1 though, so the second element could always be the same as the first.
class X {
getSeveralArrays() {
for (let index = 0; index < 50; index++) {
this.getValue();
}
}
getValue() {
this.i++;
this.array = [];
this.randomArray = [];
for (let index = 0; index < 4; index++) {
this.randomValue = this.getRandom();
if (this.array.length === 1) {
while (this.array[0] === this.randomValue) {
this.randomValue = this.getRandom();
}
this.array.push(this.randomValue);
} else if (this.array.length === 2) {
while (this.array[0] === this.randomValue || this.array[1] === this.randomValue) {
this.randomValue = this.getRandom();
}
this.array.push(this.randomValue);
} else if (this.array.length === 3) {
while (
this.array[0] === this.randomValue ||
this.array[1] === this.randomValue ||
this.array[2] === this.randomValue
) {
this.randomValue = this.getRandom();
}
this.array.push(this.randomValue);
} else {
this.array.push(this.randomValue);
}
console.log({ ...this.array });
this.randomArray.push({ ind: this.i, val: this.array });
}
}
getRandom() {
const value = Math.floor(Math.random() * 4);
return value;
}
}
console.log(new X().getSeveralArrays());
Also, all those checks can be simplified:
while (this.array.some(value => value === this.randomValue)) {
this.randomValue = this.getRandom();
}
And generally, just as a small code review: If you do not need to access something from another class method (or somewhere outside), you should not put all those values into class properties, but keep them as values inside your functions.
So this.randomValue and this.array should just be defined within your function with let or const.

ng-pattern for mobile number validation

I am trying to implement mobile number validation on a Visualforce page using Angular JS, but am having problems getting my head around how to write the regex expression.
The requirements, as given to me, are fairly simple:
The number should be 10 digits long (I've already set the maxlength attribute on the field so this one is kind of taken care of already)
It should start with 04 (as it is an Australian mobile)
Only numbers should be allowed.
The regex expression I am using (in the ng-pattern attribute for my phone number input field) is:
^/(04)[0-9]{10}/$
This works up to a point - it does not allow anything other than numbers and does let me enter a 10 digit number starting with 04. However it also lets me enter numbers starting with, for example, 02, 03 etc....
Probably quite a simple thing I'm missing but I've had a look at quite a few sites, including this one, and can't find the answer.
Any help would be hugely appreciated as this one has caused me a few grey hairs already.
Try using this pattern
Use this in ur HTML file:
<input type="text" (keypress)="keyPress($event)" minlength=10 maxlength=10>
Use this in ur JS file:
keyPress(event: any) {
const pattern = /[0-9\+\-\ ]/;
let inputChar = String.fromCharCode(event.charCode);
if (event.keyCode != 8 && !pattern.test(inputChar)) {
event.preventDefault();
}
}
Try this one:
Mobile Number :
//inside view:
<input type="text" class="form-control" ng-model="mobileNo" name="mobileNo" ng-pattern="regEx" />
//inside controller:
$scope.regEx="/^[0-9]{10,10}$/";
For starters I had to create a whole js function for it... and it does validates as you type. here is my full code I hope this can help you get where you need.
This function gets the string every time a key is beign pressed and it allows the carrete to move front, back, delete and backspace. check it out and let me know if it helps you. you can run it on any situation and this is how I would add the "04" validation
//phone validation 10 digits and parenthesis (344)567-0011
function validatePhone(inputId) {
let validKey = false;
const input = document.getElementById(inputId);
let enteredDigits = input.value;
//switch to remove the country code added by default on autoComplete forms.
if (enteredDigits.length > 10 && enteredDigits[0] == '+') {
switch (enteredDigits.length) {
case 12:
enteredDigits = enteredDigits.slice(2);
break;
case 13:
enteredDigits = enteredDigits.slice(3);
break;
case 14:
enteredDigits = enteredDigits.slice(4);
break;
default:
enteredDigits = enteredDigits.replace(/\D+/g, '');
}
}
let newPhone = enteredDigits.replace(/\D+/g, ''); // This replace any character that is not a number.
const key = event.keyCode || event.charCode; // Get the pressed key.
let caretPosition = input.selectionStart; // get the carret position.
// splits, removes the "-" and converts from array to string and gives the needed digits.
const areaCode = newPhone.split('').splice(0, 3).toString().replace(/,/g, '');
const threeDigit = newPhone.split('').splice(3, 3).toString().replace(/,/g, '');
const fourDigit = newPhone.split('').splice(6, 8).toString().replace(/,/g, '');
// Moving carret on different positions. when the numeric keys are being pressed.
// Key >= 48 && key <= 58 number keys.
// Key >= 96 && key <= 105 numeric path number keys.
if ((key >= 48 && key <= 58) || (key >= 96 && key <= 105)) {
validKey = true;
if (threeDigit.length > 0) {
if (caretPosition == 1) {
caretPosition = caretPosition + 1;
} else if (caretPosition == 4 && newPhone.length == 4) {
caretPosition = caretPosition + 2;
} else if (caretPosition == 4 && newPhone.length >= 5) {
caretPosition = caretPosition + 1;
} else if (caretPosition == 5) {
caretPosition = caretPosition + 1;
} else if (caretPosition >= 2 && caretPosition <= 3 && newPhone.length <= 4) {
caretPosition = caretPosition + 1;
}
}
if (fourDigit.length > 0 && caretPosition == 9) {
caretPosition = caretPosition + 1;
}
}
// Key = 8 = Backspace.
else if (key == 8) {
validKey = true;
if (caretPosition == 3 && newPhone.length == 3) {
caretPosition = caretPosition - 1;
} else if (caretPosition == 2 && newPhone.length == 3) {
caretPosition = caretPosition - 1;
} else if (caretPosition == 1 && newPhone.length == 3 && threeDigit.length == 0) {
caretPosition = caretPosition - 1;
}
}
// Key = 46 = Delete. Key =37 = ArrowLeft. Key = 39 = ArrowRight.
else if (key == 46 || key == 39 || key == 37) {
validKey = true;
// Delete
if (key == 46) {
if (caretPosition == 0 && newPhone.length > 3) {
caretPosition = caretPosition + 1;
} else if (caretPosition == 1 && newPhone.length == 3) {
caretPosition = caretPosition - 1;
} else if (caretPosition == 2 && newPhone.length == 3) {
caretPosition = caretPosition - 1;
} else if (caretPosition == 3 && newPhone.length == 3) {
caretPosition = caretPosition - 1;
} else if ((newPhone.length >= 4 && caretPosition == 4) || (newPhone.length >= 4 && caretPosition == 8)) {
caretPosition = caretPosition + 1;
}
}
}
//here is the validation for the country that you need.
if ((newPhone.length == 1 && newPhone[0] != '0') || (newPhone.length >= 2 && newPhone[1] != '4')) {
alert('Must start with 04');
newPhone = '';
}
// Adding the special character for formatting.
if (threeDigit.length > 0 && fourDigit.length == 0) {
newPhone = '(' + areaCode + ')' + threeDigit;
} else if (fourDigit.length > 0 && threeDigit.length == 3) {
newPhone = '(' + areaCode + ')' + threeDigit + '-' + fourDigit;
}
if (!validKey) {
caretPosition = caretPosition - 1;
}
// Set new values.
newPhone = newPhone.substring(0, 13);
input.value = newPhone;
input.focus();
input.setSelectionRange(caretPosition, caretPosition);
}
<form name="myForm"
onsubmit="return validateForm()"
method="post">
Phone number: <input type="text"
id="phoneNumber"
name="fPhone"
onkeyup="validatePhone('phoneNumber')">
<input type="submit"
value="Submit">
</form>

D3 import .csv to 2Darray & opacity change when hover

I'm currently writing a visualization via D3 and I hope you can help me out.
To get an idea of what I'm making you can view this link: https://dl.dropboxusercontent.com/u/56480311/Data-visualization/index.html
I'm facing two problems: the first is that I can't seem to place .csv data in a 2D array. I found multiplie tutorials about placing it in a normal array but the only solution I came up with if your data is in a table, is to use a 2D array. I couldn't find how to do this so what I thought would help:
var lines = []; //define lines as an array
//retrieve data from .csv file
d3.csv("https://dl.dropboxusercontent.com/u/56480311/Data-visualization/growth-prep.csv", function(data) {
lines = data.map(function(d) {
return d;
});
});
//create 2D array named myArray
var myArray = new Array(10);
for (var i = 0; i < 10; i++) {
myArray[i] = new Array(18);
}
//place each value of .csv file into myArray
for (var j = 0; j < lines.length; j++) {
var values = lines[j].split(";");
for (var k = 0; k < values.length; k++) {
myArray[k][j] = values[k];
}
}
This code doesn't work, however. Console keeps saying that the arrays are undefined and they're empty.
A second problem I'm facing is in visualizing the data. I sum three values that are next to each other (so for example dataset[0][0] + dataset[0][1] + dataset[0][2]). I draw this value as the width of a rectangle. On top of that, I want to draw three different rectangles each with the value of one of three. So in this case there is one rectangle consisting of dataset[0][0] + dataset[0][1] + dataset[0][2] and on top there is a rectangle showing data dataset[0][0], one showing data dataset[0][1] and a third showing data dataset[0][2]. I want the three smaller ones only to appear once the mouse hovers over the 'sum' / parent rectangle.
If you view the link you can see what I mean. Everything is already there, only the three smaller rectangles have opacity 0 so you don't see them yet (but you can find them via inspect elements).
I figured I could do this by setting the opacity of the three rectangles to 0 and to 1 once the mouse hovers. The best solution to me would be to place the three rectangles into one kind of div. Once the mouse hovers over it, its opacity is 1. Only I can't figure out how to easily give different class names without having to do it by hand for each rectangle separately. Does anyone know how to do this or else have a better solution to change the opacity of all three rectangles once the mouse hovers over the 'bigger' rectangle?
This is the code:
var dataset = [[6,6,3,3,3,0,6,6,0,12,6,6,0,0,18,6,3,3],[3,0,0,6,3,0,3,3,0,9,3,0,0,0,18,6,6,6],[3,0,3,6,3,3,6,0,3,9,6,3,0,0,15,6,6,6],[6,6,3,3,0,3,6,6,6,12,6,6,0,0,18,6,6,3],[6,6,0,6,0,0,6,6,6,12,6,6,0,0,24,6,6,0],[3,6,3,6,3,3,6,6,3,3,0,0,0,0,15,3,9,6],[3,3,0,3,0,3,3,3,3,9,3,0,0,0,15,6,3,9],[0,0,0,3,0,6,6,3,3,3,0,3,0,0,24,6,12,6],[6,6,3,6,0,0,9,9,6,12,6,6,0,0,15,3,3,3],[6,6,0,6,3,0,6,6,0,9,6,3,0,0,9,3,6,0]];
var h = 800;
var w = 800;
//create svg of 800x800px
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var xPos = 150;
for (var k = 0; k < 10; k++) { //loop through lines of array
var yPos = 40 + k*80;
for (var j = 0; j < 18; j++) { //loop through rows of array
var count = j + 1;
//assign data of three boxes to value1/value2/value3 with which we will later on draw three separate rectangles to visualize the data
if (count == 1 || count == 4 || count == 7 || count == 10 || count == 13 || count == 16) {
var value1 = dataset[k][j];
}
if (count == 2 || count == 5 || count == 8 || count == 11 || count == 14 || count == 17) {
var value2 = dataset[k][j];
}
if (count == 3 || count == 6 || count == 9 || count == 12 || count == 15 || count == 18) {
var value3 = dataset[k][j];
}
if (count % 3 ==0) {
var sum = dataset[k][j] + dataset[k][j-1] + dataset[k][j-2]; //count the three values to also draw one bigger rectangle of their sum
var rectangle = svg.append("rect")
.attr("x", xPos)
.attr("y", yPos)
.attr("width", sum*5)
.attr("height", 20)
.attr("fill", function(d) {
if (count == 3) {
return "LightSeaGreen";
}
else if (count == 6) {
return "MediumSeaGreen";
}
else if (count == 9) {
return "MediumSpringGreen";
}
else if (count == 12) {
return "LimeGreen";
}
else if (count == 15) {
return "ForestGreen"
}
else if (count == 18) {
return "GreenYellow"
}
});
for (var l = 0; l < 3; l++) { //draw three 'sub' rectangles on top of the one 'sum' rectangle. they should appear when the mouse hovers over their 'sum' rectangle
var rectangle2 = svg.append("rect")
.attr("class", "sqr")
.attr("x", function() {
if (l == 0) {
return xPos;
} else if (l == 1) {
return xPos + value1*5;
} else if (l == 2) {
return xPos + (value1+value2)*5;
}
})
.attr("y", yPos)
.attr("width", function() {
if (l == 0) {
return value1*5;
} else if (l == 1) {
return value2*5;
} else if (l == 2) {
return value3*5;
}
})
.attr("height", 20)
.attr("fill", function() {
if (l == 0) {
return "SteelBlue";
} else if (l == 1) {
return "aquamarine";
} else if (l == 2) {
return "SkyBlue";
}
})
.attr("opacity", 0); //in first instance the rectangles are not visible. Opacity should turn to 1 when the mouse hovers over their according div
}
if (sum > 0) {
xPos = xPos + sum*5 + 5;
}
}
}
xPos = 150;
}

ExtJS4 hbox layout issue

We are using ExtJS4 in our application.But we are facing an issue with hbox layout.We need to displat the items from right side.Normally in ExtJS4,items in hbox layout start from left side and move towards right side.But we need to start from right side and move towards left side.I think we need to change the order in ExtJS4 library(box layout).
ExtJS4 box layout is:
/*
This file is part of Ext JS 4
Copyright (c) 2011 Sencha Inc
Contact: http://www.sencha.com/contact
GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
*/
Ext.define('Ext.layout.container.Box', {
alias: ['layout.box'],
extend: 'Ext.layout.container.Container',
alternateClassName: 'Ext.layout.BoxLayout'
requires: [
'Ext.layout.container.boxOverflow.None',
'Ext.layout.container.boxOverflow.Menu',
'Ext.layout.container.boxOverflow.Scroller',
'Ext.util.Format',
'Ext.dd.DragDropManager'
],
defaultMargins: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
padding: '0',
type: 'box',
scrollOffset: 0,
itemCls: Ext.baseCSSPrefix + 'box-item',
targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
innerCls: Ext.baseCSSPrefix + 'box-inner',
bindToOwnerCtContainer: true,
fixedLayout: false,
availableSpaceOffset: 0,
reserveOffset: true,
clearInnerCtOnLayout: false,
flexSortFn: function (a, b) {
var maxParallelPrefix = 'max' + this.parallelPrefixCap,
infiniteValue = Infinity;
a = a.component[maxParallelPrefix] || infiniteValue;
b = b.component[maxParallelPrefix] || infiniteValue;
// IE 6/7 Don't like Infinity - Infinity...
if (!isFinite(a) && !isFinite(b)) {
return false;
}
return a - b;
},
// Sort into *descending* order.
minSizeSortFn: function(a, b) {
return b.available - a.available;
},
constructor: function(config) {
var me = this;
me.callParent(arguments);
me.flexSortFn = Ext.Function.bind(me.flexSortFn, me);
me.initOverflowHandler();
},
getChildBox: function(child) {
child = child.el || this.owner.getComponent(child).el;
return {
left: child.getLeft(true),
top: child.getTop(true),
width: child.getWidth(),
height: child.getHeight()
};
},
calculateChildBox: function(child) {
var me = this,
boxes = me.calculateChildBoxes(me.getVisibleItems(), me.getLayoutTargetSize()).boxes,
ln = boxes.length,
i = 0;
child = me.owner.getComponent(child);
for (; i < ln; i++) {
if (boxes[i].component === child) {
return boxes[i];
}
}
},
calculateChildBoxes: function(visibleItems, targetSize) {
var me = this,
math = Math,
mmax = math.max,
infiniteValue = Infinity,
undefinedValue,
parallelPrefix = me.parallelPrefix,
parallelPrefixCap = me.parallelPrefixCap,
perpendicularPrefix = me.perpendicularPrefix,
perpendicularPrefixCap = me.perpendicularPrefixCap,
parallelMinString = 'min' + parallelPrefixCap,
perpendicularMinString = 'min' + perpendicularPrefixCap,
perpendicularMaxString = 'max' + perpendicularPrefixCap,
parallelSize = targetSize[parallelPrefix] - me.scrollOffset,
perpendicularSize = targetSize[perpendicularPrefix],
padding = me.padding,
parallelOffset = padding[me.parallelBefore],
paddingParallel = parallelOffset + padding[me.parallelAfter],
perpendicularOffset = padding[me.perpendicularLeftTop],
paddingPerpendicular = perpendicularOffset + padding[me.perpendicularRightBottom],
availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),
isStart = me.pack == 'start',
isCenter = me.pack == 'center',
isEnd = me.pack == 'end',
constrain = Ext.Number.constrain,
visibleCount = visibleItems.length,
nonFlexSize = 0,
totalFlex = 0,
desiredSize = 0,
minimumSize = 0,
maxSize = 0,
boxes = [],
minSizes = [],
calculatedWidth,
i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall,
tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff,
flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset,
perpendicularMargins, stretchSize;
for (i = 0; i < visibleCount; i++) {
child = visibleItems[i];
childPerpendicular = child[perpendicularPrefix];
me.layoutItem(child);
childMargins = child.margins;
parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];
tmpObj = {
component: child,
margins: childMargins
};
// flex and not 'auto' width
if (child.flex) {
totalFlex += child.flex;
childParallel = undefinedValue;
}
// Not flexed or 'auto' width or undefined width
else {
if (!(child[parallelPrefix] && childPerpendicular)) {
childSize = child.getSize();
}
childParallel = child[parallelPrefix] || childSize[parallelPrefix];
childPerpendicular = childPerpendicular || childSize[perpendicularPrefix];
}
nonFlexSize += parallelMargins + (childParallel || 0);
desiredSize += parallelMargins + (child.flex ? child[parallelMinString] || 0 : childParallel);
minimumSize += parallelMargins + (child[parallelMinString] || childParallel || 0);
// Max height for align - force layout of non-laid out subcontainers without a numeric height
if (typeof childPerpendicular != 'number') {
// Clear any static sizing and revert to flow so we can get a proper measurement
childPerpendicular = child['get' + perpendicularPrefixCap]();
}
// Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
tmpObj[parallelPrefix] = childParallel || undefinedValue;
tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
boxes.push(tmpObj);
}
shortfall = desiredSize - parallelSize;
tooNarrow = minimumSize > parallelSize;
//the space available to the flexed items
availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));
if (tooNarrow) {
for (i = 0; i < visibleCount; i++) {
box = boxes[i];
minSize = visibleItems[i][parallelMinString] || visibleItems[i][parallelPrefix] || box[parallelPrefix];
box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
box[parallelPrefix] = minSize;
}
}
else {
if (shortfall > 0) {
for (i = 0; i < visibleCount; i++) {
item = visibleItems[i];
minSize = item[parallelMinString] || 0;
if (item.flex) {
box = boxes[i];
box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
box[parallelPrefix] = minSize;
}
else {
minSizes.push({
minSize: minSize,
available: boxes[i][parallelPrefix] - minSize,
index: i
});
}
}
Ext.Array.sort(minSizes, me.minSizeSortFn);
for (i = 0, length = minSizes.length; i < length; i++) {
itemIndex = minSizes[i].index;
if (itemIndex == undefinedValue) {
continue;
}
item = visibleItems[itemIndex];
minSize = minSizes[i].minSize;
box = boxes[itemIndex];
oldSize = box[parallelPrefix];
newSize = mmax(minSize, oldSize - math.ceil(shortfall / (length - i)));
reduction = oldSize - newSize;
box.dirtySize = box.dirtySize || box[parallelPrefix] != newSize;
box[parallelPrefix] = newSize;
shortfall -= reduction;
}
}
else {
remainingSpace = availableSpace;
remainingFlex = totalFlex;
flexedBoxes = [];
for (i = 0; i < visibleCount; i++) {
child = visibleItems[i];
if (isStart && child.flex) {
flexedBoxes.push(boxes[Ext.Array.indexOf(visibleItems, child)]);
}
}
Ext.Array.sort(flexedBoxes, me.flexSortFn);
for (i = 0; i < flexedBoxes.length; i++) {
calcs = flexedBoxes[i];
child = calcs.component;
childMargins = calcs.margins;
flexedSize = math.ceil((child.flex / remainingFlex) * remainingSpace);
flexedSize = Math.max(child['min' + parallelPrefixCap] || 0, math.min(child['max' + parallelPrefixCap] || infiniteValue, flexedSize));
remainingSpace -= flexedSize;
remainingFlex -= child.flex;
calcs.dirtySize = calcs.dirtySize || calcs[parallelPrefix] != flexedSize;
calcs[parallelPrefix] = flexedSize;
}
}
}
if (isCenter) {
parallelOffset += availableSpace / 2;
}
else if (isEnd) {
parallelOffset += availableSpace;
}
if (me.owner.dock && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) && !me.owner.width && me.direction == 'vertical') {
calculatedWidth = maxSize + me.owner.el.getPadding('lr') + me.owner.el.getBorderWidth('lr');
if (me.owner.frameSize) {
calculatedWidth += me.owner.frameSize.left + me.owner.frameSize.right;
}
availPerpendicularSize = Math.min(availPerpendicularSize, targetSize.width = maxSize + padding.left + padding.right);
}
//finally, calculate the left and top position of each item
for (i = 0; i < visibleCount; i++) {
child = visibleItems[i];
calcs = boxes[i];
childMargins = calcs.margins;
perpendicularMargins = childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom];
parallelOffset += childMargins[me.parallelBefore];
calcs[me.parallelBefore] = parallelOffset;
calcs[me.perpendicularLeftTop] = perpendicularOffset + childMargins[me.perpendicularLeftTop];
if (me.align == 'stretch') {
stretchSize = constrain(availPerpendicularSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
calcs[perpendicularPrefix] = stretchSize;
}
else if (me.align == 'stretchmax') {
stretchSize = constrain(maxSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
calcs[perpendicularPrefix] = stretchSize;
}
else if (me.align == me.alignCenteringString) {
// When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
// the size to yield the space available to center within.
// The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
diff = mmax(availPerpendicularSize, maxSize) - me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB) - calcs[perpendicularPrefix];
if (diff > 0) {
calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
}
}
// Advance past the box size and the "after" margin
parallelOffset += (calcs[parallelPrefix] || 0) + childMargins[me.parallelAfter];
}
return {
boxes: boxes,
meta : {
calculatedWidth: calculatedWidth,
maxSize: maxSize,
nonFlexSize: nonFlexSize,
desiredSize: desiredSize,
minimumSize: minimumSize,
shortfall: shortfall,
tooNarrow: tooNarrow
}
};
},
onRemove: function(comp){
this.callParent(arguments);
if (this.overflowHandler) {
this.overflowHandler.onRemove(comp);
}
},
initOverflowHandler: function() {
var handler = this.overflowHandler;
if (typeof handler == 'string') {
handler = {
type: handler
};
}
var handlerType = 'None';
if (handler && handler.type !== undefined) {
handlerType = handler.type;
}
var constructor = Ext.layout.container.boxOverflow[handlerType];
if (constructor[this.type]) {
constructor = constructor[this.type];
}
this.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, this, handler);
},
onLayout: function() {
this.callParent();
// Clear the innerCt size so it doesn't influence the child items.
if (this.clearInnerCtOnLayout === true && this.adjustmentPass !== true) {
this.innerCt.setSize(null, null);
}
var me = this,
targetSize = me.getLayoutTargetSize(),
items = me.getVisibleItems(),
calcs = me.calculateChildBoxes(items, targetSize),
boxes = calcs.boxes,
meta = calcs.meta,
handler, method, results;
if (me.autoSize && calcs.meta.desiredSize) {
targetSize[me.parallelPrefix] = calcs.meta.desiredSize;
}
//invoke the overflow handler, if one is configured
if (meta.shortfall > 0) {
handler = me.overflowHandler;
method = meta.tooNarrow ? 'handleOverflow': 'clearOverflow';
results = handler[method](calcs, targetSize);
if (results) {
if (results.targetSize) {
targetSize = results.targetSize;
}
if (results.recalculate) {
items = me.getVisibleItems(owner);
calcs = me.calculateChildBoxes(items, targetSize);
boxes = calcs.boxes;
}
}
} else {
me.overflowHandler.clearOverflow();
}
me.layoutTargetLastSize = targetSize;
me.childBoxCache = calcs;
me.updateInnerCtSize(targetSize, calcs);
me.updateChildBoxes(boxes);
me.handleTargetOverflow(targetSize);
},
updateChildBoxes: function(boxes) {
var me = this,
i = 0,
length = boxes.length,
animQueue = [],
dd = Ext.dd.DDM.getDDById(me.innerCt.id), // Any DD active on this layout's element (The BoxReorderer plugin does this.)
oldBox, newBox, changed, comp, boxAnim, animCallback;
for (; i < length; i++) {
newBox = boxes[i];
comp = newBox.component;
// If a Component is being drag/dropped, skip positioning it.
// Accomodate the BoxReorderer plugin: Its current dragEl must not be positioned by the layout
if (dd && (dd.getDragEl() === comp.el.dom)) {
continue;
}
changed = false;
oldBox = me.getChildBox(comp);
// If we are animating, we build up an array of Anim config objects, one for each
// child Component which has any changed box properties. Those with unchanged
// properties are not animated.
if (me.animate) {
// Animate may be a config object containing callback.
animCallback = me.animate.callback || me.animate;
boxAnim = {
layoutAnimation: true, // Component Target handler must use set*Calculated*Size
target: comp,
from: {},
to: {},
listeners: {}
};
// Only set from and to properties when there's a change.
// Perform as few Component setter methods as possible.
// Temporarily set the property values that we are not animating
// so that doComponentLayout does not auto-size them.
if (!isNaN(newBox.width) && (newBox.width != oldBox.width)) {
changed = true;
// boxAnim.from.width = oldBox.width;
boxAnim.to.width = newBox.width;
}
if (!isNaN(newBox.height) && (newBox.height != oldBox.height)) {
changed = true;
// boxAnim.from.height = oldBox.height;
boxAnim.to.height = newBox.height;
}
if (!isNaN(newBox.left) && (newBox.left != oldBox.left)) {
changed = true;
// boxAnim.from.left = oldBox.left;
boxAnim.to.left = newBox.left;
}
if (!isNaN(newBox.top) && (newBox.top != oldBox.top)) {
changed = true;
// boxAnim.from.top = oldBox.top;
boxAnim.to.top = newBox.top;
}
if (changed) {
animQueue.push(boxAnim);
}
} else {
if (newBox.dirtySize) {
if (newBox.width !== oldBox.width || newBox.height !== oldBox.height) {
me.setItemSize(comp, newBox.width, newBox.height);
}
}
// Don't set positions to NaN
if (isNaN(newBox.left) || isNaN(newBox.top)) {
continue;
}
comp.setPosition(newBox.left, newBox.top);
}
}
// Kick off any queued animations
length = animQueue.length;
if (length) {
// A function which cleans up when a Component's animation is done.
// The last one to finish calls the callback.
var afterAnimate = function(anim) {
// When we've animated all changed boxes into position, clear our busy flag and call the callback.
length -= 1;
if (!length) {
me.layoutBusy = false;
if (Ext.isFunction(animCallback)) {
animCallback();
}
}
};
var beforeAnimate = function() {
me.layoutBusy = true;
};
// Start each box animation off
for (i = 0, length = animQueue.length; i < length; i++) {
boxAnim = animQueue[i];
// Clean up the Component after. Clean up the *layout* after the last animation finishes
boxAnim.listeners.afteranimate = afterAnimate;
// The layout is busy during animation, and may not be called, so set the flag when the first animation begins
if (!i) {
boxAnim.listeners.beforeanimate = beforeAnimate;
}
if (me.animate.duration) {
boxAnim.duration = me.animate.duration;
}
comp = boxAnim.target;
delete boxAnim.target;
// Stop any currently running animation
comp.stopAnimation();
comp.animate(boxAnim);
}
}
},
updateInnerCtSize: function(tSize, calcs) {
var me = this,
mmax = Math.max,
align = me.align,
padding = me.padding,
width = tSize.width,
height = tSize.height,
meta = calcs.meta,
innerCtWidth,
innerCtHeight;
if (me.direction == 'horizontal') {
innerCtWidth = width;
innerCtHeight = meta.maxSize + padding.top + padding.bottom + me.innerCt.getBorderWidth('tb');
if (align == 'stretch') {
innerCtHeight = height;
}
else if (align == 'middle') {
innerCtHeight = mmax(height, innerCtHeight);
}
} else {
innerCtHeight = height;
innerCtWidth = meta.maxSize + padding.left + padding.right + me.innerCt.getBorderWidth('lr');
if (align == 'stretch') {
innerCtWidth = width;
}
else if (align == 'center') {
innerCtWidth = mmax(width, innerCtWidth);
}
}
me.getRenderTarget().setSize(innerCtWidth || undefined, innerCtHeight || undefined);
// If a calculated width has been found (and this only happens for auto-width vertical docked Components in old Microsoft browsers)
// then, if the Component has not assumed the size of its content, set it to do so.
if (meta.calculatedWidth && me.owner.el.getWidth() > meta.calculatedWidth) {
me.owner.el.setWidth(meta.calculatedWidth);
}
if (me.innerCt.dom.scrollTop) {
me.innerCt.dom.scrollTop = 0;
}
},
handleTargetOverflow: function(previousTargetSize) {
var target = this.getTarget(),
overflow = target.getStyle('overflow'),
newTargetSize;
if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
newTargetSize = this.getLayoutTargetSize();
if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height) {
this.adjustmentPass = true;
this.onLayout();
return true;
}
}
delete this.adjustmentPass;
},
// private
isValidParent : function(item, target, position) {
// Note: Box layouts do not care about order within the innerCt element because it's an absolutely positioning layout
// We only care whether the item is a direct child of the innerCt element.
var itemEl = item.el ? item.el.dom : Ext.getDom(item);
return (itemEl && this.innerCt && itemEl.parentNode === this.innerCt.dom) || false;
},
// Overridden method from AbstractContainer.
// Used in the base AbstractLayout.beforeLayout method to render all items into.
getRenderTarget: function() {
if (!this.innerCt) {
// the innerCt prevents wrapping and shuffling while the container is resizing
this.innerCt = this.getTarget().createChild({
cls: this.innerCls,
role: 'presentation'
});
this.padding = Ext.util.Format.parseBox(this.padding);
}
return this.innerCt;
},
// private
renderItem: function(item, target) {
this.callParent(arguments);
var me = this,
itemEl = item.getEl(),
style = itemEl.dom.style,
margins = item.margins || item.margin;
// Parse the item's margin/margins specification
if (margins) {
if (Ext.isString(margins) || Ext.isNumber(margins)) {
margins = Ext.util.Format.parseBox(margins);
} else {
Ext.applyIf(margins, {top: 0, right: 0, bottom: 0, left: 0});
}
} else {
margins = Ext.apply({}, me.defaultMargins);
}
// Add any before/after CSS margins to the configured margins, and zero the CSS margins
margins.top += itemEl.getMargin('t');
margins.right += itemEl.getMargin('r');
margins.bottom += itemEl.getMargin('b');
margins.left += itemEl.getMargin('l');
style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';
// Item must reference calculated margins.
item.margins = margins;
},
destroy: function() {
Ext.destroy(this.overflowHandler);
this.callParent(arguments);
}
});
Help would be appreciated.
You just need to set your layout config, like this:
Ext.create('Ext.panel.Panel', {
layout: {type: 'hbox', pack:'end'}
});
The key there is pack:
Controls how the child items of the container are packed together. Acceptable configuration values for this property are:
'start' : Default
child items are packed together at left side of container
'center' :
child items are packed together at mid-width of container
'end' :
child items are packed together at right side of container
Hope that helps

Resources