J'ai un viewModel avec un tas de nombres avec beaucoup de décimales. Si mes fixations ressemblent à ceci:
<tr>
<td data-bind="text: Date"></td>
<td data-bind="text: ActualWeight"></td>
<td data-bind="text: TrendWeight"></td>
</tr>
Ensuite, bien sûr, la sortie a toutes les décimales et est très illisible. Changer les liaisons pour ressembler à ceci résout le problème, mais est très bavard et "bruyant":
<tr>
<td data-bind="text: Date"></td>
<td data-bind="text: ActualWeight().toFixed(1)"></td>
<td data-bind="text: TrendWeight().toFixed(1)"></td>
</tr>
Remarque, ceci est un petit extrait et devoir ajouter .toFixed (1) chaque fois que je lie un nombre conduit à un balisage beaucoup plus compliqué que ce qui est montré ici.
Pour tout sauf les nombres, remplacer la chaîne toString a été un moyen efficace pour moi de contrôler à quoi ressemble la sortie. Avez-vous des suggestions sur la façon de dire une fois le knockout, d'une manière centrale pour ma page, quelle fonction utiliser pour convertir les nombres en chaînes avant qu'ils ne soient ajoutés à la sortie?
D'ailleurs, avoir une manière générale de dire à KO comment formater n'importe quel type de valeur semble utile. Le remplacement de Date.prototype.toString fonctionne mais semble un peu lourd car il peut avoir un impact sur d'autres utilisations de .toString en plus des knockout.
Il existe plusieurs façons de gérer une situation comme celle-ci. Vous pouvez choisir de l'adresser via des liaisons ou de l'insérer dans votre modèle de vue.
Si votre modèle de vue est créé par le plug-in de mappage et que vous ne souhaitez pas personnaliser la façon dont il est créé, vous pouvez envisager d'utiliser une liaison personnalisée qui est un wrapper à la liaison de texte pour gérer la mise en forme.
Quelque chose comme ( http://jsfiddle.net/rniemeyer/RVL6q/ ):
ko.bindingHandlers.numericText = {
update: function(element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()),
precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericText.defaultPrecision,
formattedValue = value.toFixed(precision);
ko.bindingHandlers.text.update(element, function() { return formattedValue; });
},
defaultPrecision: 1
};
Il serait certainement possible de créer une liaison encore plus générique (formatedText) qui inspecterait la valeur et la formaterait en utilisant des valeurs par défaut remplaçables ou vous permettrait de passer des options de formatage ({ type: "numeric", precision: 2 }
).
Pour votre scénario, il semble que la première option pourrait être un bon choix. Cependant, si vous souhaitez le pousser dans votre modèle de vue, vous pouvez créer un observable spécial qui peut renvoyer à la fois une version formatée et une version brute de la valeur.
Cela pourrait être quelque chose comme ( http://jsfiddle.net/rniemeyer/fetBG/ ):
function formattedNumericObservable(initialValue, precision) {
var _raw = ko.observable(initialValue),
precision = precision || formattedNumericObservable.defaultPrecision,
//the dependentObservable that we will return
result = ko.dependentObservable({
read: function() {
return _raw().toFixed(precision);
},
write: _raw
});
//expose raw value for binding
result.raw = _raw;
return result;
}
Maintenant, vous pouvez potentiellement vous lier contre myValue
et myValue.raw
Selon vos besoins. Sinon, vous pouvez le retourner et renvoyer la valeur brute par défaut et exposer un formatted
dependObservable. Lorsqu'un objet comme celui-ci est converti en JSON, il perdra l'un des "sous-observables", donc si vous renvoyez ces données à un serveur, cela pourrait être une considération.
Vous pouvez à nouveau le rendre plus générique et créer un formattedObservable
qui contiendra des informations sur la façon de formater l'objet.
Enfin, la version 1.3 beta propose une API extenders
. Vous pouvez faire quelque chose de similaire à ci-dessus comme: ( http://jsfiddle.net/rniemeyer/AsdES/ )
ko.extenders.numeric = function(target, precision) {
var result = ko.dependentObservable({
read: function() {
return target().toFixed(precision);
},
write: target
});
result.raw = target;
return result;
};
Ensuite, appliquez-le à un observable comme: var myValue = ko.observable(1.223123).extend({numeric: 1});
Vous pouvez également avoir l'extension simplement ajouter un formatted
dependObservable à target
au lieu de renvoyer le dependObservable lui-même.
Puisque knockout prend désormais en charge extenders , je les utiliserais à la place des liaisons personnalisées. La liaison ressemblerait à ceci:
<tr>
<td data-bind="text: Date.extend({format : 'date'})"></td>
<td data-bind="text: ActualWeight.extend({format : 'weight'})"></td>
<td data-bind="text: TrendWeight.extend({format : 'weight'})"></td>
</tr>
Vous devez écrire l'extension format
dans ce cas. Des exemples sont fournis dans la documentation de désactivation.
Pour formater la devise et le pourcentage, j'ai créé ma liaison numérique numeralformat.js à utiliser avec numeral.min.js trouvé à http://adamwdraper.github.com/Numeral-js/
numeralformat.js (inspiré par dateformat.js et moment.min.js)
var formatNumber = function (element, valueAccessor, allBindingsAccessor, format) {
// Provide a custom text value
var value = valueAccessor(), allBindings = allBindingsAccessor();
var numeralFormat = allBindingsAccessor.numeralFormat || format;
var strNumber = ko.utils.unwrapObservable(value);
if (strNumber) {
return numeral(strNumber).format(numeralFormat);
}
return '';
};
ko.bindingHandlers.numeraltext = {
init: function (element, valueAccessor, allBindingsAccessor) {
$(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));
},
update: function (element, valueAccessor, allBindingsAccessor) {
$(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));
}
};
ko.bindingHandlers.numeralvalue = {
init: function (element, valueAccessor, allBindingsAccessor) {
$(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));
//handle the field changing
ko.utils.registerEventHandler(element, "change", function () {
var observable = valueAccessor();
observable($(element).val());
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
$(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));
}
};
ko.bindingHandlers.percenttext = {
init: function (element, valueAccessor, allBindingsAccessor) {
$(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));
},
update: function (element, valueAccessor, allBindingsAccessor) {
$(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));
}
};
ko.bindingHandlers.percentvalue = {
init: function (element, valueAccessor, allBindingsAccessor) {
$(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));
//handle the field changing
ko.utils.registerEventHandler(element, "change", function () {
var observable = valueAccessor();
observable($(element).val());
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
$(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));
}
};
Exemples de liaisons dans View.
<td><label>Available Commitment Balance:</label> </td>
<td>
<!-- ko with: SelectedLoan -->
<span data-bind="numeraltext: AvailableCommitmentAmount"></span>
<!-- /ko -->
</td>
<td><label> % Interest Rate:</label></td>
<td>
<!-- ko with: SelectedLoan -->
<input data-bind="percentvalue: InterestRatePercent" />
<!-- /ko -->
</td>
<td><label> $ Amount To Transfer:</label></td>
<td>
<!-- ko with: SelectedLoan -->
<input class="inputsmall" data-bind="numeralvalue: FundsHeldTotalAmount" />
<!-- /ko -->
</td>
Pour s'appuyer sur la réponse acceptée ci-dessus. J'ai bifurqué RP Niemeyers pour ajouter également une mise en forme de virgule. Donc, si vous avez 10001.232, le format sera 10.001.232. Assez important si vous travaillez avec des prix. Encore une fois, cela ne fait que renforcer la réponse.
<div data-bind="numericText: myValue"></div>
<div data-bind="numericText: myValue, positions: 3"></div>
<div data-bind="numericText: myValue, positions: myPositions"></div>
<input data-bind="value: myPositions" />
<div>
<br>
just testing commas<br>
<input type=text id="withComma" readonly/>
</div>
ko.bindingHandlers.numericText = {
update: function(element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var positions= ko.utils.unwrapObservable(allBindingsAccessor().positions) || ko.bindingHandlers.numericText.defaultPositions;
var formattedValue = value.toFixed(positions);
var finalFormatted = ko.bindingHandlers.numericText.withCommas(formattedValue);
ko.bindingHandlers.text.update(element, function() { return finalFormatted ; });
},
defaultPositions: 2,
withCommas: function(original){
original+= '';
x = original.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
};
var viewModel = {
myValue: ko.observable(12673.554),
myPositions: ko.observable(4)
};
ko.applyBindings(viewModel);
/*Just testing the function below, you don't need thsi....*/
function addCommas(nStr)
{
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
var formatted = addCommas('1070781.493')
$('#withComma').val(formatted);
J'ai abordé le formatage à l'aide du plug-in jQuery Globalize. Voici ma version des gestionnaires de formatage, textFormatted
et valueFormatted
sont des wrappers pour les liaisons de texte et de valeur respectivement.
L'utilisation sera:
<span data-bind="textFormatted: Amount, pattern: 'n'" />
Facultativement, la culture peut également être spécifiée. Mais je pense que ce type de contrôle ne devrait pas appartenir au HTML, bien qu'il puisse être utile lors du développement ou du débogage ...
<input data-bind="valueFormatted: Amount, pattern: 'n', culture: 'et'" type="text" />
Les valeurs de la propriété/liaison pattern
doivent être des formats appropriés que le paramètre format
de la fonction Globalize.format( value, format, [locale] )
attend. Il en va de même pour la propriété/liaison culture
qui sera utilisée dans le paramètre facultatif locale
. Globaliser la référence.
Définitions contraignantes:
(function() {
function getFormatedOrPlainResult(value, allBindingsAccessor) {
var pattern = allBindingsAccessor.get('pattern');
if (pattern == null || !/\S*/.test(pattern)) {
return value;
}
var valueToFormat = pattern === 'd' ? new Date(value) : value;
return Globalize.format(valueToFormat, pattern, allBindingsAccessor.get('culture'));
};
ko.bindingHandlers.textFormatted = {
init: ko.bindingHandlers.text.init,
update: function(element, valueAccessor, allBindingsAccessor) {
var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor);
ko.bindingHandlers.text.update(element, function() { return result; });
}
};
ko.bindingHandlers.valueFormatted = {
init: function(element, valueAccessor, allBindingsAccessor) {
var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor);
ko.bindingHandlers.value.init(element, function() { return result; }, allBindingsAccessor);
},
update: function(element, valueAccessor, allBindingsAccessor) {
var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor);
ko.bindingHandlers.value.update(element, function() { return result; }, allBindingsAccessor);
}
};
}());
S'il s'agit simplement d'afficher un numéro localisé d'une liaison de texte, un moyen très simple consiste à utiliser toLocaleString()
<tr>
<td data-bind="text: ActualWeight().toLocaleString()"></td>
<td data-bind="text: TrendWeight().toLocaleString()"></td>
</tr>
Pour plus d'informations, visitez page .