So I am using ng-bootstraps datepicker to display some user data for each day. I use custom day template to apply certain CSS classes
<ng-template #customDay let-date>
<div
class="custom-day"
[ngClass]="evaluatePresenceType(date)"
>
{{ date.day }}
</div>
</ng-template>
The thing is this method is being called many times for each day which is less than optimal.
Is there a way to apply CSS class to every day just once, when the datepicker is being rendered and not every time I click anywhere?
When you want to use a custom template day to give some class to "specials days" you has two approach:
Use [ngClass] or [class.myClass]="function(date)" as you
indicate
Use DayTemplateData (see the docs)
Well, the doc is not very clear. The idea is to have a function,e.g.
data=(date: NgbDate, current?: {year: number, month: number})=>
{
//see that futhermore the "date" you has an object
//current with two properties: "year" and "month" that is showing
return this.calendar.getWeekday(date)>=6?'square':null
}
Then you use
<input class="form-control" [dayTemplateData]="data"
[dayTemplate]="customDay" ...>
And your template day pass the "data" using let-data=data
<ng-template #customDay let-date let-data="data" ...>
<span class="custom-day" [ngClass]="data" ...>
{{ date.day }}
</span>
</ng-template>
See that if you only want to apply an unique class your function can return true or null and use [class.myClass]="data"
In the stackblitz, I use the two approach and use two counters to show the improve of this another approach
Related
In a Flask app with the Bootstrap-Flask extension, how would one override the default style using WTForms' render_kw class parameter when the form's HTML is automatically rendered using render_form()? [*]
I have this simple Form defined that provides a button to confirm the deletion of a database record, and I'd like that button to be red instead of the standard grey color:
class DeleteMappingForm(FlaskForm):
submit = SubmitField(_l('Delete mapping'))
The auto-generated HTML (focusing just on the <input> element) is:
<input class="btn btn-secondary btn-md" id="submit" name="submit" type="submit" value="Delete mapping">
I'd like to use the btn-alert instead of the default btn-secondary Bootstrap class to display the button in red instead of grey.
The WTForms way of defining "keywords that will be given to the widget at render time" is to pass those as a dict in render_kw. That works fine to add new keywords, but it doesn't replace existing, which I tried doing like this:
class DeleteMappingForm(FlaskForm):
submit = SubmitField(_l('Delete mapping'), render_kw={'class':'btn btn-alert btn-md'})
That ends up adding the CSS classes I defined to the list of pre-defined CSS classes, ending up with this HTML:
<input class="btn btn-secondary btn-md btn btn-alert btn-md" id="submit" name="submit" type="submit" value="Delete mapping">
Is there a way to have the values passed via render_kw to override the default classes, and have just class="btn btn-alert btn-md"?
Extra information
Looking at how render_kw is handled by WTForms, it seems the values should be overriden (dict gets concatenated, which overrides the same keys, eg.:
>>> a={"class":"abc", "other":"aaa"}
>>> a
{'class': 'abc', 'other': 'aaa'}
>>> b={"class":"def", "other":"aaa"}
>>> b
{'class': 'def', 'other': 'aaa'}
>>> dict(a, **b)
{'class': 'def', 'other': 'aaa'}
I couldn't also identify a source of this in Bootstrap-Flask's handling of render_form()...
[*] I'm using the Bootstrap-Flask extension instead of the original Flask-Bootstrap because the latter unfortunately doesn't support Bootstrap 4+. render_form() is the Bootstrap-Flask equivalent of Flask-Bootstrap's quick_form().
Turns out the solution is to be found on the side of Bootstrap-Flask, and that it already provides a button_style parameter to the render_form macro, allowing to pass a Bootstrap class directly.
The following template gets me that red button I was looking for ;) As easy as that...
{% extends "base.html" %}
{% import 'bootstrap/form.html' as wtf %}
{% block app_content %}
<h1>{{ title }}</h1>
<div class="row">
<div class="col-lg-8">
{{ wtf.render_form(form, button_style="danger") }}
</div>
</div>
{% endblock %}
Well, that is kind of embarrassing - but I'm happy nonetheless to have found the solution, too bad for the time spent writing up this question, but as this might help others with the same challenge I'm adding my answer here.
We have created a component using Angular material's autocomplete. To display the options, we are traversing through an array of 51 objects. I am applying a CSS class to the already selected option. The isAccountingTypeSelected method determines whether the option was selected or not.
The method gets called 51*28 = 1428 times. I don't seem to understand the reason? It should only be called 51 times, shouldn't it?
<mat-form-field class="full-width">
<input type="text" matInput #autoCompleteInput [formControl]="autocompleteForm" [matAutocomplete]="auto" placeholder="Choose Accounting Type" aria-label="Number">
<span matSuffix class="close-icon hover" *ngIf="autoCompleteInput.value" (click)="clearAll($event)"></span>
<span matSuffix class="arrow-drop-down-icon hover" (click)="openPanel()"></span>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="accountingTypeSelected($event)">
<mat-option *ngFor="let accountingType of filteredAccountingTypes | async" [value]="accountingType.code">
<span class="accounting-type-options" [class.selected]="isAccountingTypeSelected(accountingType.code)">
{{ accountingType.name + ' (' + accountingType.code + ')' }}
</span>
</mat-option>
</mat-autocomplete>
</mat-form-field>
isAccountingTypeSelected(code: string): boolean {
console.log('I was called');
if (this.selectedAccountingTypes.find((accountingType: AccountingType) => accountingType.code === code)) {
return true;
}
return false;
}
Angular uses changedetection lifecycle multiple times to check if the function has changed for [class.selected] or ngClass. If you use function, it will call multiple times. For this reason the use of function is not advised when you bind, instead you should calculate the values in your component.ts file and just bind the values to ngClass or [class].
Example: Stackblitz
N.B: We know when we change selected value it triggers a event change, we can calculate it and attach the calculation result to the [class.my-class] or ngClass.
Angular is gonna evaluate that expression every time it checks for changes, which in your case might be the css being added to your span elements.
Calling methods from the template in a for loop is not the best approach because they are called very often. You should instead store the result in a property and bind to this property instead.
It is a bind problem. Angular checks more times the result value. You can try with ChangeDetectionStrategy.CheckOnce
Your ngFor loop needs track a specific id so it won't re-render for nothing. Try this:
<mat-option *ngFor="let accountingType of filteredAccountingTypes | async; trackBy: trackByCode"[value]="accountingType.code">
</mat-option>
Then you add this function:
trackByCode(index: number, accountingType: yourType): string {
return accountingType.code;
}
I'm operating on a symfony application and I would like to set a new variable from all controllers to all rendering.
The reason is that something in my footer has become dynamic and in compliance with the MVC pattern I'd like to put the processing of this new data in my controllers.
What is the good way to do this with symfony ?
EDIT
I am not using symfony as a REST API, the Symfony server is only serving twig rendered templates as HTML.
Details on my case :
the current twig template has hard-coded titles for a form :
<div>
<h2>Today</h2>
<!-- today's inputs .... -->
</div>
<div>
<h2>Tomorrow</h2>
<!-- tomorrow's inputs .... -->
</div>
I'd like to give to variables to my views : $today and $tomorrow.
This way I'd be able to render day names instead of today or tomorrow.
<div>
<h2>{{ today }}</h2>
<!-- today's inputs .... -->
</div>
<div>
<h2>{{ tomorrow }}</h2>
<!-- tomorrow's inputs .... -->
</div>
For example if today is Tuesday, variables has to be assigned this way :
$today = "Tuesday" and $tomorrow = "Wednesday".
What's more
This is not a question about this specific case. I'd like to now if there is a way to pass a variable to all views without editing all controllers. As I see it, I'd put a parent action to all controller to generate this variable. I just wanted to know if this is the usual way.
I don't want to use ajax calls, and I don't want to put complex twig code inside my template. I want to handle this via controllers.
Please read official documentation about using global variables.
Off the top of my head - you can inject...
...scalar values from the global twig config
...scalar values from the service container parameters
...services (read php objects)
Or you can write Twig extension, like:
class DateExtension extends \Twig_Extension
{
public function getFunctions()
{
return [
new \Twig_SimpleFunction('get_date', array($this, 'getDate'))
];
}
public function getDate($date)
{
// format it how you want
return (new \DateTime($date))->format('Y-m-d H:i:s');
}
}
And then use it in any template simply by:
<div>
<h2>{{ get_date('today') }}</h2>
<!-- today's inputs .... -->
</div>
<div>
<h2>{{ get_date('tomorrow') }}</h2>
<!-- tomorrow's inputs .... -->
</div>
About what kind of "dynamic" do you speak? If this dynamic goes from changing of some value stored in the data storage of your app, than, I belive, you could define controller action to retrive this data from, for example, your database and then call it via AJAX on every page load to obtain those value on client-side. Or maybe even use help of WebSocket's. But this is just assumption. If you really need help you should provide us more information about context of your task.
I'm curious if I can somehow use dynamic variable names in templates. For example, I'm having a loop, though a type of units in my game:
{{# config.units:unit }}
<input type="text" id="unit_{{unit}}" class="toTrain selectable" value="" placeholder="0" />
{{/ config }}
Where the value of the input should return the value of {{units_1}} for example, which represents the amount of units (type 1).
I could easily do some external object and store the amount of units for each of them but, I was wondering if I can keep the data binded because somewhere in the template there will be a total needed resources which is calculated whith these values.
The only "solution" which came into my head was to get rid of the loop and manually write the units in the template. But, when units change, I also need to change the template, and.. the real template structure for one unit is a bit bigger than this snippet.
Example:
<input value="{{units_1}}" />
<input value="{{units_2}}" />
And I was looking for something like:
<input value="{{'units_'+unit}}" />
Which is obviously not working and not even supposed to work this way. But, thats why I'm here right ? To raise questions.
Regards !
Try to use write getUnit function:
{{# config.units:unit }}
<input type="text" id="{{ getUnit(unit) }}" class="toTrain selectable" value="" placeholder="0" />
{{/ config }}
Component:
Ractive.extend({
init:function(){
self.set("getUnit", function (id) {
return self.get("config.units.unit_"+id);
});
}
})
I want to draw fields using a Handlebars partial that have the key name and value. My json is like this:
{ "someKnownField" : { "textValue" : "the value I want" } }
I want a label with someKnownField as its text, and an input with the value of textValue in it. I use a partial because I have hundreds of these fields and don't want to have to hard code their names.
Here's my partial code, called textfield
<div class="control-group">
<label class="control-label" for="input{{#key}}">{{#key}}</label>
<div class="controls">
<input type="text" id="input{{#index}}" placeholder="{{#key}}" value="{{textValue}}">
</div>
</div>
Now, I can't use a {{#with}} helper, a-la {{#with someKnownField}}{{> textfield}}{{/with}} since a with doesn't give you a #key. {{#each}} has a #key but its of the context within the each node (textValue); So how do you key the key name OF the each node itself?
This does not work, but demonstrates what I need to grab:
<label>{{../#key}}</label>
since it's expecting an id in the parent path, not a calculated value (which doesn't exist anyway, since it's not an array itself).
You've done well, but made a typo. The correct way:
<label>{{#../key}}</label>