还在学习......我有一个区域,其参数与其他字段绑定。在这个区域内,我希望用户能够调整任何参数,或自定义编辑SQL查询,甚至粘贴自己的参数,然后单击“获取数据”来执行SQL命令。
理想情况下,此区域看起来是同一个框(使用一个textArea,交换两个textAreas,或执行此text / textArea交换)。我最大的障碍是让更新坚持下去。我怀疑它与dependentObsevable有关,但我无法打破试用/错误周期。现在,我有“获取数据”按钮,连接到下面的框中显示调整后的文本,而不是实际发送命令。
我也相信所选择的值逻辑应该作为一个函数在“selected”可观察中,但只是不确定如何实现。非常感谢您的眼睛和反馈。谢谢!
这是JSFiddle。
HTML:
<b style="width: 800px; height: 163px;" data-bind="visible: !editing(), text: queryBuilder(), click: edit"> </b>
<textarea style="width: 800px; height: 163px;" data-bind="visible: editing, value: queryBuilder(), hasFocus: editing, valueUpdate: 'afterkeydown'"></textarea>
<button data-bind="click: update">Get Data</button>
查看型号:
var giveBack = ko.observable("nothing");
//Query Builder for the text area
self.queryBuilder = ko.dependentObservable(function () {
//var giveBack = ko.observable("nothing");
if (self.selected() == 0) giveBack = self.getTransByHourQuery;
if (self.selected() == 1) giveBack = self.getTransByHourQuery2;
return giveBack;
}, this);
self.update = function(){
return self.query(giveBack);
};
答案 0 :(得分:0)
您需要2个单独的可观察对象,一个用于非编辑模式,另一个用于编辑模式。
self.rawQuery = ko.observable();
self.queryBuilder = ko.computed( function() {
var q1 = self.getTransByHourQuery();
var q2 = self.getTransByHourQuery2();
var raw = self.rawQuery();
var selected = self.selected();
switch( selected ) {
case "0":
// Set current "raw" to this query
self.rawQuery(q1);
return q1;
case "1":
// Set current "raw" to this query
self.rawQuery(q2);
return q2;
default:
return raw;
}
});
进入编辑模式时清除所选选项
self.edit = function () {
self.editing(true)
self.selected(undefined);
};
在组合框中添加一个占位符,以便我们可以清除所选的observable并将rawQuery值放入queryBuilder。
<select data-bind="options: querySelector(), optionsText: 'name', optionsValue: 'id', value: selected, optionsCaption: 'select...'"></select>
将click绑定移动到td元素,而不是b元素,这样当rawQuery为空且选中为空时,您可以单击某些内容
因为我使用的是计算机,你需要更改b元素文本绑定以从文本绑定值中删除()
<b style="width: 800px; height: 163px;" data-bind="visible: !editing(), text: queryBuilder"> </b>
将textarea的值切换为rawQuery并删除valueUpdate绑定。
<textarea style="width: 800px; height: 163px;" data-bind="visible: editing, value: rawQuery, hasFocus: editing"></textarea>
我还在第一行的每个输入数据绑定中添加了启用:选择。
现在你有2个observable,你应该能够从rawQuery手动更新回顶部输入框,但这将是棘手的。最好的办法是使用正则表达式来尝试匹配您的参数。
下面的代码有效,但它有点hacky;)
首先附上&#34;匹配&#34;关闭用作参数的每个observable的正则表达式模式。我们稍后会用它。
var buildParam = function( value, matchRx ) {
var result = ko.observable(value);
result.matchRx = matchRx;
return result;
};
self.startDate = buildParam("02/01/2014 12:00 AM", /\d{2}\/\d{2}\/\d{4} \d{2}:\d{2} (?:AM|PM)/);
self.endDate = buildParam("03/30/2014 12:00 AM", /\d{2}\/\d{2}\/\d{4} \d{2}:\d{2} (?:AM|PM)/);
self.serviceType = buildParam("401", /\d+/);
self.channelID = buildParam("101", /\d+/);
接下来创建一个构建查询定义的函数
var buildQueryDef = function() {
// Get the arguments, first is the query, all the remaining are observables
var theArgs = [].splice.call(arguments, 0);
// Start building the object. shift the first arg off directly off as the query
var def = {
query: theArgs.shift()
};
// The remaining elements in the array now all observables.
// Create a computed to convert the parameters placeholders to real values.
def.transformed = ko.computed( function() {
var result = this.query;
var index = 0;
theArgs.forEach( function(item) {
// replace {@p1} with first observable value, and so on
result = result.replace( new RegExp( "\{\@p" + (index++) + "\}", "g" ), item());
} );
return result;
}, def);
// Create a function that matches text back to the original query.
def.doMatch = function( text ) {
// Convert any special regex control characters to literals and convert spaces to '\s+'
var src = this.query.replace( /[\(\)\[\]]/g, "\\$&").replace( /[ ]+/g, "\\s+");
var index = 0;
// Replace the parameter placeholder with the regex from the parameter observable
theArgs.forEach( function(item) {
src = src.replace( new RegExp( "\{\@p" + (index++) + "\}", "g" ), "(" + item.matchRx.source + ")");
} );
// Match whole string, allow trailing spaces
src = "^\s*" + src + "\s*$";
return { src: src, matches: text.match( new RegExp(src) ) };
}.bind(def);
// Update the observables from the match set.
def.setObservables = function(matches) {
// Ignore first match as it's the entire string
for(var index = 1; index < matches.length; index++) {
theArgs[index-1](matches[index]);
}
}.bind(def);
return def;
};
从查询SQL构建每个查询def。我已经更新了您的原始SQL以包含您串联字符串的参数占位符(希望您不要介意!)
self.queryDefs = {
'0': buildQueryDef("SELECT " +
"TABLE_ID as TABLE, " +
"DATEPART(HH,CREATE_DATE) AS HOUR, " +
"CAST(CREATE_DATE AS DATE) AS DATE, " +
"COUNT(TRANSACTION_ID) as TRANSACTION_COUNT " +
"FROM " +
"[TRANSACTION_SUMMARY] " +
"WHERE " +
"CREATE_DATE BETWEEN '{@p0}' AND '{@p1}' " +
"AND SERVICE_TYPE = {@p2} " +
"AND TABLE_ID= {@p3}", this.startDate, this.endDate, this.serviceType, this.channelID ),
'1': buildQueryDef("SELECT " +
"TABLE_ID as TABLE2, " +
"DATEPART(HH,CREATE_DATE) AS HOUR2, " +
"CAST(CREATE_DATE AS DATE) AS DATE2, " +
"COUNT(TRANSACTION_ID) as TRANSACTION_COUNT2 " +
"FROM " +
"[TRANSACTION_SUMMARY] " +
"WHERE " +
"CREATE_DATE BETWEEN '{@p0}' AND '{@p1}' " +
"AND SERVICE_TYPE = {@p2} " +
"AND TABLE_ID= {@p3}", this.startDate, this.endDate, this.serviceType, this.channelID )
};
注意参数索引与传递给函数的observable顺序之间的相关性,也就是&#34; key&#34;每个条目对应于&#34; id&#34;支持商店的选择框。
queryBuilder computed现在可以使用queryDefs对象,使用selected()可观察值作为键。
self.queryBuilder = ko.computed( function() {
var selected = self.selected();
if ( self.queryDefs[selected] ) {
var result = self.queryDefs[selected].transformed();
self.rawQuery(result);
return result;
} else
return self.rawQuery();
});
添加几个订阅编辑和rawQuery以运行上面的匹配系统
self.editing.subscribe( function(isEdit) {
if ( !isEdit && ( self.rawQuery.isDirty != true )) {
// force a refresh if the observable wasn't changed
// otherwise the queryDefs won't match back up
self.rawQuery.notifySubscribers(self.rawQuery());
self.rawQuery.isDirty = false;
}
});
self.rawQuery.subscribe( function(text) {
if ( self.selected() ){
return;
}
self.rawQuery.isDirty = true;
for(var query in self.queryDefs) {
var def = self.queryDefs[query];
var result = def.doMatch(text);
if ( !result.matches )
continue;
self.selected(query);
def.setObservables( result.matches );
return;
}
});
isDirty标志用于检测用户何时点击&#34;编辑&#34;但是没有做出改变。在那种情况下,rawQuery订阅不会触发,选择框也不会重新选择已定义的查询,因此我们需要在编辑恢复为false时手动强制通知。
在创建一个包含这些更新的新jsFiddle时,您可以使用它。