79
Views
12
Comments
Solved
Display costume CSS based on different conditions

Hello!


I need to change CSS for buttons based on different conditions. I am using button group and setting button value from static entity: 


This is the desired outcome: 

1. Red border and text is displayed when button is selected.  This is only one, currently pressed button.

2. Grey background is displayed when IsCompleted attribute from entity is True. There are multiple records with IsCompleted = True. If button is grey, it does not change colour even if it is pressed. 

3. Red background is set when IsCurrent attribute from entity is True. There is only one record with isCurrent=True. If button is red, it does not change colour even if pressed. 

4. Grey border to everything else. 


Right now in Style class I have this expression: 

If (GetCurrentMilestones.List.Current.Milestones.Id =  Entities.Milestones.TwoWeeksPrior, "button-milestone-current", If (GetFinishedMilestones.List.Current.Milestones.Id = Entities.Milestones.TwoWeeksPrior, "button-milestone-finished",
If (SelectedMilestoneId = Entities.Milestones.TwoWeeksPrior, "button-milestone-selected", "button-milestone")))

*GetCurrentMilestone aggregate contains only one entry of currently active (not pressed) button that is supposed to have red background. 

*GetFinishedMilestones aggregate contains multiple records that are supposed to have grey background. 

*SelectedMilestoneId is local variable that is set when some button is clicked. This button has to have red border.


The problem is, that grey background is showing only to last element in GetFinishedMilestones list. Is there any way to check if record exists in record list and then, depending on the result, change CSS? 

I am making progressive web app. 


Here is my GetFinishedMilestones aggregate :


Here is Milestone entity: 


Button CSS: 

.button-milestone{
    height: 65px;
    min-width: 80px;
    border-radius: 5px;
    margin-right: 15px;
    color: #898989;
    font-family: "OpenSans-Bold";
    font-size: 14px;
    text-align: center;
    box-sizing: border-box;
    border: 1px solid #C0C0C0;
    border-radius: 5px;
    background-color: transparent;
    white-space: pre-line;
}

.button-milestone-selected{
    height: 65px;
    min-width: 80px;
    border-radius: 5px;
    margin-right: 15px;
    color: #EA5532;
    font-family: "OpenSans-Bold";
    font-size: 14px;
    text-align: center;
    box-sizing: border-box;
    border: 1px solid #EA5532;
    border-radius: 5px;
    background-color: transparent;
    white-space: pre-line;
}

.button-milestone-current{
    height: 65px;
    min-width: 80px;
    margin-right: 15px;
    font-family: "OpenSans-Bold";
    font-size: 14px;
    text-align: center;
    box-sizing: border-box;
    border: none;
    border-radius: 5px;
    white-space: pre-line;
    background-color: #EA5532;
    color: #FFFFFF;
}

.button-milestone-finished{
    height: 65px;
    min-width: 80px;
    margin-right: 15px;
    font-family: "OpenSans-Bold";
    font-size: 14px;
    text-align: center;
    box-sizing: border-box;
    border: none;
    border-radius: 5px;
    white-space: pre-line;
    background-color: #898989;
    color: #FFFFFF;
}


Thank you!

Best regards,

Sandra 

Rank: #136
Solution

Hi Sandra,


I didn't realise this wasn't intended to be a static entity in the end result.  So as you can't open other peoples oml's, here's an attempt at explaining what you could do :


You basically want to have a different style for a widget (in this case a button, but could be anything) dependent on 2 things, some details of the milestone record this widget represents, and whether the (underlying record of the) widget is currently 'selected' by the user of your screen, right ?

So, for starters, you create your css, with all the different styles.  I have added a selected and unselected variant for each status for completeness.


SyntaxEditor Code Snippet

/*style that is always valid, for all milestones*/
.milestone-all{
    width: 160px;
    height:160px;
    font-size: 18px;
    font-weight: bolder;
}

/*style of completed milestone*/
.milestone-completed-selected{
    background-color: darkgray;
    color: lightgray;
    border: 3px solid darkorange;
    font-size: 24px;
    font-style: italic;
}

.milestone-completed-unselected{
    background-color: darkgray;
    color: lightgray;
    border: 3px solid lightgray;
}


/*style of current milestone*/
.milestone-current-selected{
    background-color: darkorange;
    color: whitesmoke;
    border: 3px solid whitesmoke;
    font-size: 24px;
    font-style: italic;
}
.milestone-current-unselected{
    background-color: darkorange;
    color: whitesmoke;
}


/*default style of milestone, if not current and not completed*/
.milestone-default-selected{
    background-color: whitesmoke;
    color: darkorange;
    border: 3px solid darkorange;
    font-size: 24px;
    font-style: italic;
}
.milestone-default-unselected{
    background-color: whitesmoke;
    color: darkgray;
    border: 1px solid darkgray;
}

Now, for applying these classes :

I think a lot of your confusion comes from trying to involve many different aggregates with different filters, I think there's absolutely no need for that.

So let's assume you want to create a number of buttons next to each other, each button representing another milestone in your table.  For this, you will need one single aggregate retrieving a list of all the milestone records that you want to have a button for.  As an added calculated attribute, add IsSelected.

In your screen add a local variable, of type MilestoneId, holding the currently selected value.  In your aggregate, in the formula for the IsSelected attribute, compare the id to this local variable.  See below, with a test value of 1 for the local variable, you can see the top one is selected, others are false.



Now for creating buttons for these milestones : put a list widget on your screen, and use as source the aggregate above.  Put as single item in your list a button, with an expression widget inside of it instead of a text widget.  Set the expression to the name of the current milestone of the list.




How to keep track of selected milestone : add ButtonOnClick event, and in here, set the local selected id to the current one clicked in the list, followed by a refresh of the aggregate.

And now for where the different style options in the CSS come together with the buttons on the screen : add a class attribute to button, is visible above, but full content is this :


SyntaxEditor Code Snippet

"btn milestone-all " 
+ If(GetMilestones.List.Current.Milestone.IsCompleted,"milestone-completed",If(GetMilestones.List.Current.Milestone.IsCurrent,"milestone-current","milestone-default"))
+ If(GetMilestones.List.Current.IsSelected,"-selected","-unselected")

top part makes sure that all buttons look like buttons and with the added styling defined in milestone-all

the second part looks at IsCompleted and IsCurrent to decide between styling for current, complete or default

the last part appends the bit -selected or -unselected dependent on the IsSelected calculated aggregate field.


As I can't share an oml with you, you can try out here


hope this helps show you a way to do this,

Dorine

mvp_badge
MVP
Rank: #91

Hi Sandra,

I'm just guessing, could you please try the below CSS style condition.

Code Snippet

If (SelectedMilestoneId = GetCurrentMilestones.List.Current.Milestones.Id, 
    "button-milestone-selected",
    If (GetFinishedMilestones.List.Current.Milestones.IsCompleted, 
            "button-milestone-finished",
                If (GetCurrentMilestones.List.Current.Milestones.Id =  Entities.Milestones.TwoWeeksPrior, 
                    "button-milestone-current",
                        "button-milestone")))


which application your are referring... Reactive? Traditional?

Is the button inside the List widget? If possible could you please mentioned the CSS class definition as well?


Regards,

Benjith Sam

mvp_badge
MVP
Rank: #91

Hi Sandra,

Thank you for the information. Could you please try the below mentioned Style Class conditional statement.

Code Snippet

If (GetFinishedMilestones.List.Current.Milestones.IsCompleted, 
            "button-milestone-finished",                
                If(GetFinishedMilestones.List.Current.Milestones.Is_Active, 
                    "button-milestone-current",
                        If (SelectedMilestoneId = GetCurrentMilestones.List.Current.Milestones.Id, 
                            "button-milestone-selected",     
                                "button-milestone")))


Hope this helps you!


Regards,

Benjith Sam

Rank: #136

Hi Sandra,


your expression is complex, and also having these extra aggregates, one for getting the current milestones and one for the finished milestones adds complexity.  You are not even iterating through them by the looks if it, so that would even add more complexity.

I think you could greatly simplify things by adding a cssClass attribute to your static entity, cause that's what it is, right ?  In fact, I would add 2 attributes, one for the selected css and one for the unselected, that way you can even add subtle difference between a finished or an unfinished milestone being selected if you want.

Then you just fill the class extended property with the value for each milestone, and there you go.

see attached oml for what i mean.

Dorine

DemoMilestoneButtons.oml

Hi,


I think the solution that Dorine wrote is perfect for you. You can create a new attribute to your static entity where you put the css class for each record and take that attribute to your style classes. It simplifies the complexity and the performance.


Best regards,

Ricardo M Pereira

Rank: #136
Solution

Hi Sandra,


I didn't realise this wasn't intended to be a static entity in the end result.  So as you can't open other peoples oml's, here's an attempt at explaining what you could do :


You basically want to have a different style for a widget (in this case a button, but could be anything) dependent on 2 things, some details of the milestone record this widget represents, and whether the (underlying record of the) widget is currently 'selected' by the user of your screen, right ?

So, for starters, you create your css, with all the different styles.  I have added a selected and unselected variant for each status for completeness.


SyntaxEditor Code Snippet

/*style that is always valid, for all milestones*/
.milestone-all{
    width: 160px;
    height:160px;
    font-size: 18px;
    font-weight: bolder;
}

/*style of completed milestone*/
.milestone-completed-selected{
    background-color: darkgray;
    color: lightgray;
    border: 3px solid darkorange;
    font-size: 24px;
    font-style: italic;
}

.milestone-completed-unselected{
    background-color: darkgray;
    color: lightgray;
    border: 3px solid lightgray;
}


/*style of current milestone*/
.milestone-current-selected{
    background-color: darkorange;
    color: whitesmoke;
    border: 3px solid whitesmoke;
    font-size: 24px;
    font-style: italic;
}
.milestone-current-unselected{
    background-color: darkorange;
    color: whitesmoke;
}


/*default style of milestone, if not current and not completed*/
.milestone-default-selected{
    background-color: whitesmoke;
    color: darkorange;
    border: 3px solid darkorange;
    font-size: 24px;
    font-style: italic;
}
.milestone-default-unselected{
    background-color: whitesmoke;
    color: darkgray;
    border: 1px solid darkgray;
}

Now, for applying these classes :

I think a lot of your confusion comes from trying to involve many different aggregates with different filters, I think there's absolutely no need for that.

So let's assume you want to create a number of buttons next to each other, each button representing another milestone in your table.  For this, you will need one single aggregate retrieving a list of all the milestone records that you want to have a button for.  As an added calculated attribute, add IsSelected.

In your screen add a local variable, of type MilestoneId, holding the currently selected value.  In your aggregate, in the formula for the IsSelected attribute, compare the id to this local variable.  See below, with a test value of 1 for the local variable, you can see the top one is selected, others are false.



Now for creating buttons for these milestones : put a list widget on your screen, and use as source the aggregate above.  Put as single item in your list a button, with an expression widget inside of it instead of a text widget.  Set the expression to the name of the current milestone of the list.




How to keep track of selected milestone : add ButtonOnClick event, and in here, set the local selected id to the current one clicked in the list, followed by a refresh of the aggregate.

And now for where the different style options in the CSS come together with the buttons on the screen : add a class attribute to button, is visible above, but full content is this :


SyntaxEditor Code Snippet

"btn milestone-all " 
+ If(GetMilestones.List.Current.Milestone.IsCompleted,"milestone-completed",If(GetMilestones.List.Current.Milestone.IsCurrent,"milestone-current","milestone-default"))
+ If(GetMilestones.List.Current.IsSelected,"-selected","-unselected")

top part makes sure that all buttons look like buttons and with the added styling defined in milestone-all

the second part looks at IsCompleted and IsCurrent to decide between styling for current, complete or default

the last part appends the bit -selected or -unselected dependent on the IsSelected calculated aggregate field.


As I can't share an oml with you, you can try out here


hope this helps show you a way to do this,

Dorine