Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Edit form for some kind of Russian Dolls container(s) with AngularJS

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 :

  • The black box can only contain blue, green and red,
  • The red box can only contain green and yellow,
  • The yellow box can contain nothing,
  • The other boxes (green & blue) can contain anything

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

like image 724
Julo0sS Avatar asked Dec 02 '15 14:12

Julo0sS


People also ask

Can you create a dynamic form in angular?

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.

How do I create multiple forms in angular?

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.

How to use ngfor for a control inside a formarray?

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.


1 Answers

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/

like image 63
Keval Bhatt Avatar answered Sep 19 '22 05:09

Keval Bhatt