I can't wrap my head around this. What am I overlooking?
Here is a minimal sample: https://plnkr.co/edit/VjqGeG9JpHblyLBb?preview
<tnt:InfoLabel
text="{
path: 'LastName',
formatter: '.formatter.typeText'
}"
colorScheme="{
path: 'LastName',
formatter: '.formatter.typeColor'
}" />
// formatter.js
sap.ui.define([], function () {
"use strict";
return {
typeText: function(sLastName) {
// Called with 'sLastName' value
},
typeColor: function(sLastName) {
// Not called
}
};
});
I'm using UI5 1.79 with sap.ui.model.odata.v4.ODataModel.
Add targetType: 'any' to the property binding info that has the issue. E.g.:
<tnt:InfoLabel
text="{
path: 'LastName',
formatter: '.getMyText'
}"
colorScheme="{
path: 'LastName',
formatter: '.getMyColorScheme',
targetType: 'any'
}"
/>
With sap.ui.model.odata.v4.ODataModel, data types in property bindings are automatically determined according to the EDM type of the entity property. I.e. in the case above: even without having a certain type explicitly assigned to the text property, the v4.ODataPropertyBinding automatically picks the String type (because LastName has Type="Edm.String" in $metadata) and assigns it to the type:
<tnt:InfoLabel
text="{
path: 'LastName',
formatter: '.getMyText',
type: 'sap.ui.model.odata.type.String' <-- automatically added by v4.ODataPropertyBinding
}"
This was fine for the text property since it actually awaits a string value, but doing the same for other properties, such as colorScheme which awaits an int value, results in a FormatException.*
In order to prevent the automatic Type Determination, the targetType: 'any' has to be added.
* With commit:4611772, which is available as of 1.80, we can see the corresponding error message in the console:
FormatException in property 'colorScheme' of 'Element sap.tnt.InfoLabel#...': <LastName value> is not a valid int value. Hint: single properties referenced in composite bindings and within binding expressions are automatically converted into the type of the bound control property, unless a different 'targetType' is specified. targetType:'any' may avoid the conversion and lead to the expected behavior.
Related
I'm using Nest.js with Typeorm and library class-transformer:
import { Transform } from 'class-transformer';
#PrimaryGeneratedColumn()
#Transform(
({ value }) => `${value}/${moment().format('MM-YYYY')}`,
)
invoiceNumber: string;
I'm trying to generate somethink like this: 1/01-2022. But still I have only an number e.g 1 (without date).
How I can add date to incremented value?
You can use the transformer option.
Specifies a value transformer (or array of value transformers) that is to be used to (un)marshal this column when reading or writing to the database. In case of an array, the value transformers will be applied in the natural order from entityValue to databaseValue, and in reverse order from databaseValue to entityValue.
Source: TypeORM Documentation
transformer has two methods:
to: Used to marshal data when writing to the database.
from: Used to unmarshal data when reading from the database.
class YourClass {
#Column({
primary: true, // Marks column as primary
transformer: {
to(value) {
// Transform 'invoiceNumber'
return `${value}/${moment().format('MM-YYYY')}`;
}
from(value) {
// Do nothing
return value;
}
},
/* Other options... */
})
invoiceNumber: string;
}
Note that the decorator is no more #PrimaryGeneratedColumn but a "simple" #Column with primary option set to true.
The previous decorator is only used as a table-generated primary column.
Column it creates is primary and its value is auto-generated.
I'm using Knockout 3 with the plugin jqAutocomplete by Ryan Niemeyer. I have a problem with this model:
var ViewModel = function() {
var self = this;
self.myOptionsObs = ko.observableArray([
{ id: ko.observable(1), name: ko.observable("item 1 o"), description: ko.observable("item label 1 o") },
{ id: ko.observable(2), name: ko.observable("item 2 o"), description: ko.observable("item label 2 o") },
{ id: ko.observable(3), name: ko.observable("item 3 o"), description: ko.observable("item label 3 o") }
]);
self.myValueObs = ko.observable();
};
ko.applyBindings(new ViewModel());
<input data-bind="jqAuto: { source: myOptionsObs, value: myValueObs, inputProp: 'name', template: 'itemTmpl' }" />
As you can see, there is an observable array and each element is also an observable.
The autocomplete don't work well. As you can see in this Fiddle, the left column has an observable array but its elements aren't observable. If you click in the left box and write something, a list of options appear.
But in the right column, you have the same, but the element's are all observable. If you click in the right box and write something, when the list appear, if you move the cursor up and down, you could see that the row 'name' gets deleted and filled with zeros.
What I have to change in my data-bind attribute?
This question is related with this question.
I have to say that this solution works ok for me. But the updated plugin don't.
Thanks !!
The jqAutoComplete plugin isn't setup to work with observable properties (although it could be enhanced to do so without much work).
For now, I think that your best bet is to create a computed that will always return a plain and up-to-date version of your options.
self.myOptionsObs.plain = ko.computed(function() {
return ko.toJS(self.myOptionsObs);
});
Sample: http://jsfiddle.net/rniemeyer/45cepL9b/
I'll try to take a look at some point about supporting observable properties. Shouldn't take many changes.
I'm working with the Esprima parser, it outputs an AST format which is compatible with the Mozilla Spider Monkey Parser API.
In the Mozilla Docs, it specifies the Function node as:
interface Function <: Node {
id: Identifier | null;
params: [ Pattern ];
defaults: [ Expression ];
rest: Identifier | null;
body: BlockStatement | Expression;
generator: boolean;
expression: boolean;
}
What will the defaults property contain? It always appears as just an empty array.
defaults of Mozilla JS AST contains ES6 default parameter values.
For example,
function t(i = 20) { }
defaults will be [{ type: 'Literal', value: 20 }].
Because it is based on ES6 draft, Esprima master branch doesn't recognize it.
I have the following
Rails HAML:
= select_tag "some-class",
options_for_select([['None', '']], ''),
{ class: 'some-other-class',
'ng-model' => 'someModel',
'ng-options' => 'option.name for option in someList',
'ng-change' => 'updateSelected()'}
Angular Controller:
scope.updateSelected = ->
#logic for updating model lives here. Model updates successfully by using some values defined within scope. Includes the following:
scope.someModel = "some_new_value"
Angular Directive:
SomeClassDirective= ->
restrict: 'C'
link: (scope, element, attrs) ->
monitorFormFields = (newValue, oldValue) ->
console.log "this is the inner function call"
#logic for setting the inner _destroy field lives here
scope.$watch 'someModel', monitorFormFields
However, when the Select List value is changed, 'this is the inner function call' never prints.(it does print when the directive first initializes, ie at page load). My question therefore is: Why isn't the $watch expression triggering, and how do I get it to trigger?
Thanks!
With this HTML:
<select class="some-class" ng-model="someModel"
ng-options="option.name for option in someList"></select>
Here is a directive that will watch for a change to someModel:
myApp.directive('someClass', function () {
return {
restrict: 'C',
link: function (scope, element, attrs) {
var monitorFormFields = function (newValue, oldValue) {
console.log("this is in the inner function call");
}
scope.$watch('someModel', monitorFormFields);
}
}
});
Controller:
$scope.someList = [{ name: 'name1' }, { name: 'name2' }];
Note that you don't need to call a controller method to update someModel -- Angular does that automatically for us because of the ng-model attribute. So, the directive only needs to $watch for a change to that $scope property.
Fiddle.
I would like to from the element fetch a sibling with [_destroy] in the name and set it to either "0" or "1" depending on the value of the select box.
A more Angular approach would be to have model properties control whether "0" or "1" is displayed. E.g., in your controller:
$scope.destroy1 = "0";
$scope.destroy2 = "0";
In your HTML:
<div>{{destroy1}}</div>
<div>{{destroy2}}</div>
In monitorFormFields() you can change the values of these scope properties, and the view will automatically update -- there is no need to "find" siblings or update .val()ues.
ExtJS4 grid anticipates appropriate editor (cellEditor or rowEditor) per column.
If a column's header field is dateField - date selector will be applied on every row in that column.
What I need is an editor with different field editors per row, not per column.
The Extjs3 solution is provided here - unfortunately doesn't fit in Extjs4 case.
(please check that link to see explanatory images, cause I can't post images yet)
There's also a single column solution called property grid, but again - it supports only one column and is very deviated from the standard Ext.grid component
I have tried manually changing grid editor by customizing column.field and reloading grid.editingPlugin.editor, but always get a blank rowEditor panel with no fields.
//by default rowEditor applies textField to all cells - I'm trying to force custom numberFiled on apropriate row
var numberField=Ext.form.field.Number();
grid.columns[0].field=numberField;
//destroy current rowEditor's instance
delete grid.editingPlugin.editor;
//now, upon doubleClick on apropriate cell it should reinitialize itself (initEditor()) - and it does, but is an empty panel
what am I missing here? once I delete editingPlugin.editor everything should start from the beginning like during the first time rowEditor is called, but it looses all the fields
Solution for Ext4:
I was looking for a solution for this and this guy said the property grid has this behavior.
I have adapted it to work in a clean way for me
on initComponent I declared:
this.editors = {
'date' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Date', {selectOnFocus: true})}),
'string' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Text', {selectOnFocus: true})}),
'number' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Number', {selectOnFocus: true})}),
'int' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Number', {selectOnFocus: true})}),
'boolean' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.ComboBox', {
editable: false,
store: [[ true, 'Sim' ], [false, 'Não' ]]
})})
};
I used these functions to help me (copied):
this.renderCell = function(val, meta, rec) {
var result = val;
if (Ext.isDate(val)) {
result = me.renderDate(val);
} else if (Ext.isBoolean(val)) {
result = me.renderBool(val);
}
return Ext.util.Format.htmlEncode(result);
};
this.getCellEditor = function(record, column) {
return this.editors[record.get('type')];
};
And finally, associate these functions to the column:
{text: "Valor", name : 'colunaValor', width: 75, sortable: true, dataIndex: 'valor', width:200,
renderer: Ext.Function.bind(this.renderCell, this),
getEditor: Ext.Function.bind(this.getCellEditor, this)
}