Here is the problem,
I actually have to manage objects that can contain other objects defined in db. So, for example, I have 5 kind of boxes. A red box, a green box, a blue box, a yellow box and a black box.
Each box can contain one box, that can also contain a box, and so on.
What I receive is this kind of object :
{
"id":1,
"type":"black",
"box":
{
"id":8,
"type":"red",
"box":
{
"id":15,
"type":"green",
"box":null
}
}
}
So this example is : a black box, containing a red box, containing an empty green box. (black -> red -> green -> empty)
There are conditions :
What I need to do is some kind of "box set editor", I receive a box object, that is complex or not (meaning that it can have only one box level, or several). I have to represent it in a list of select boxes, so, for the example I wrote it will show this :
<select name="LEVEL_1">
<option value="0">NONE</option>
<option selected value="1">black</option>
<option value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
<option value="10">yellow</option>
</select>
<br/>
<select name="LEVEL_2">
<option value="0">NONE</option>
<option selected value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
</select>
<br/>
<select name="LEVEL_3">
<option value="0">NONE</option>
<option selected value="15">green</option>
<option value="10">yellow</option>
</select>
<br/>
<select name="LEVEL_4">
<option selected value="0">NONE</option>
<option value="15">green</option>
<option value="8">red</option>
<option value="3">blue</option>
<option value="10">yellow</option>
<option value="1">black</option>
</select>
This has to be achieved with AngularJS.
The whole example is coming on a table, so the boxes are displayed as a table this way :
<table>
<thead style="font-weight:bold;">
<tr style="background-color:lightblue;">
<td>Id</td>
<td>Type</td>
<td>Contains (sum)</td>
</tr>
</thead>
<tbody>
<tr ng-click="setCurrentBox();" style="background-color:lightgreen;">
<td>1</td>
<td>black</td>
<td>2 boxes</td>
</tr>
</tbody>
</table>
Notice the ng-click
part. The setCurrentBox()
function is defined in the controller, and it sets, as $scope.currentBox
, the box object received from the "BoxService
".
Click on the row will call the BoxService
, retrieve the json object for the selected box (completely! with the contained boxes into it, as written at top of the thread), and assign it to the $scope.currentBox
variable.
Change a box selection value should "empty" the next possible choice (set "none" as selected and add the possible choices as options) and, if there are child boxes then just erase them (change black choice to red in my example black->red->green->empty would give red->empty (None -selected- and green and yellow options).
In my case, I only have direct access to $scope.currentBox
. And the boxes that "currentBox
" contains are properties. So, somehow I think I should do some kind of if object.box!=null
then read box... But I'm a bit lost about it...
Well, I don't know if I'm clear enough in my problem definition, here is a short fiddle that should "show where I want to get" in this kind of "Russian Dolls" problematic...
http://jsfiddle.net/z267dquk/2/
Update 1 : http://jsfiddle.net/0js7q638/
thanks for reading / help
Update 2 : Here is an example of what I exactly mean as my question/What I'd like to make/What I miss does not seem to be clear.
Concrete example - START SITUATION :
Box object :
Box 0 (black one)
contains Box 1 (red one)
contains Box 2 (green one)
contains Box 3 (green one)
contains Box 4 (green one)
contains nothing (yet)
When user selects box 0 in the table he gets this object :
{
"id":"1",
"type":"black",
"box":{
"id":"8",
"type":"red",
"box":{
"id":"15",
"type":"green",
"box":{
"id":"15",
"type":"green",
"box":{
"id":"15",
"type":"green",
"box":null
}
}
}
}
}
This object has to be displayed into editable select boxes as follows :
Box 0 (all box colors choices available here!):
<!--This select contains all possible choices since it is the very first choice possible, no dependency-->
<select name="box0">
<option value="">NO CHOICE</option>
<option selected value="1">black</option>
<option value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
<option value="10">yellow</option>
</select>
<br/>Box 1 (contained in box 0 box property) :
<!--This select contains only boxes choices that a black box can get (since it depends of box 0 value)-->
<select name="box1">
<option value="">NO CHOICE</option>
<option selected value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
</select>
<br/>Box 2 (contained in box 1 box property) :
<!--This select contains only boxes choices that a red box can get (since it depends of box 1 value)-->
<select name="box2">
<option value="">NO CHOICE</option>
<option selected value="15">green</option>
<option value="10">yellow</option>
</select>
<br/>Box 3 (contained in box 2 box property) :
<!--This select contains only boxes choices that a green box can get (since it depends of box 2 value)-->
<select name="box3">
<option value="">NO CHOICE</option>
<option value="1">black</option>
<option value="8">red</option>
<option selected value="15">green</option>
<option value="3">blue</option>
<option value="10">yellow</option>
</select>
<br/>Box 4 (contained in box 3 box property) :
<!--This select contains only boxes choices that a green box can get (since it depends of box 3 value)-->
<select name="box4">
<option value="">NO CHOICE</option>
<option value="1">black</option>
<option value="8">red</option>
<option selected value="15">green</option>
<option value="3">blue</option>
<option value="10">yellow</option>
</select>
<br/>Box 5 (empty box ready to be filled in box 4 property) :
<!--This select contains only boxes choices that a green box can get (since it depends of box 4 value)-->
<!--This select has default selected value set as null since box4 box property is not set (box 4 box property is not a box, box 4 contains nothing)-->
<select name="box5">
<option value="" selected>NO CHOICE</option>
<option value="1">black</option>
<option value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
<option value="10">yellow</option>
</select>
CONCRETE EXAMPLE : USER ACTION 1 :
If user sets box 2 as NO CHOICE OR YELLOW (since yellow box cannot contain any box), then the current box object should look like this :
{
"id":"1",
"type":"black",
"box":{
"id":"8",
"type":"red",
"box":{
"id":"15",
"type":"green",
"box":null
}
}
}
And the HTML part should turn like this :
Box 0 (all box colors choices available here!):
<!--This select contains all possible choices since it is the very first choice possible, no dependency-->
<select name="box0">
<option value="">NO CHOICE</option>
<option selected value="1">black</option>
<option value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
<option value="10">yellow</option>
</select>
<br/>Box 1 (contained in box 0 box property) :
<!--This select contains only boxes choices that a black box can get (since it depends of box 0 value)-->
<select name="box1">
<option value="">NO CHOICE</option>
<option selected value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
</select>
<br/>Box 2 (contained in box 1 box property) :
<!--This select contains only boxes choices that a red box can get (since it depends of box 1 value)-->
<select name="box2">
<option selected value="">NO CHOICE</option>
<option value="15">green</option>
<option value="10">yellow</option>
</select>
CONCRETE EXAMPLE : USER ACTION 1 :
If user sets box 1 as BLUE, then the current box object should look like this :
{
"id":"1",
"type":"black",
"box":{
"id":"3",
"type":"blue",
"box":null
}
}
And the HTML part should turn like this :
Box 0 (all box colors choices available here!):
<!--This select contains all possible choices since it is the very first choice possible, no dependency-->
<select name="box0">
<option value="">NO CHOICE</option>
<option selected value="1">black</option>
<option value="8">red</option>
<option value="15">green</option>
<option value="3">blue</option>
<option value="10">yellow</option>
</select>
<br/>Box 1 (contained in box 0 box property) :
<!--This select contains only boxes choices that a black box can get (since it depends of box 0 value)-->
<select name="box1">
<option value="">NO CHOICE</option>
<option value="8">red</option>
<option value="15">green</option>
<option selected value="3">blue</option>
</select>
<br/>Box 2 (contained in box 1 box property) :
<!--This select contains only boxes choices that a blue box can get (since it depends of box 1 value)-->
<select name="box2">
<option selected value="">NO CHOICE</option>
<option value="15">green</option>
<option value="8">red</option>
<option value="3">blue</option>
<option value="10">yellow</option>
<option value="1">black</option>
</select>
Note that I can get the possible choices for a box, or all possible choices for any box from the BoxService
. This HAS TO come from BoxService
. This data can be huge, it is small in this example, but this can be a long list of objects that can be contained in another one.
Hope this example can make my question more clear.
Thanks for reading
This is a very basic example of how a dynamic form can be created. And since you're smart, I'm sure you noticed that this example has its limits. One area where it is lacking is validating input. So go ahead, take it from here, and add some superpowers to make it a honking-powerful, dynamic Angular form.
Creating multiple forms using FormGroup and FormControl can be very lengthy and repetitive. So, to help with it, Angular provides a service called FormBuilder. It provides the syntactic sugar that shortens the syntax to create instances of FormControl, FormGroup and FormArray. Import the FormBuilder class.
For a control inside, FormArray id must be set dynamically, and interpolation with loop index can be used for that. If the user does not provide a value for name or age control, you can show the validation message as shown below: To get a particular control, you use ngFor index value and then name of the control.
Try this example: http://jsfiddle.net/kevalbhatt18/0js7q638/1/
Using checkInnerObject function it will return count of 'box' see in example
function checkInnerObject(obj) {
var i = 0;
var arg = Array.prototype.slice.call(arguments, 1);
start: while (obj) {
if (obj.hasOwnProperty(arg)) {
obj = obj[arg];
i = i + 1;
continue start;
}
}
return i - 1;
}
checkInnerObject(OBJECT,'key you want to find');
UPDATE:
Eample : http://jsfiddle.net/kevalbhatt18/0js7q638/5/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With