Select a complex object in a drop down list and get additional data - jsviews

I use jsViews to build an application.
At some place, I have an array of complex objects. The array is bound in a dropdown list where I can set the label and the value to properties of my object.
However, I have to get also some other properties of my custom object.
How can I do that?
Right now I have :
(function($) {
var dataVm = {
value: null,
choices: [
{ "label" : "France", "value" : "FR", "icon" : "flag-icon-fr" },
{ "label" : "Germany", "value" : "DE", "icon" : "flag-icon-de" },
{ "label" : "Brazil", "value" : "BR", "icon" : "flag-icon-br" },
{ "label" : "USA", "value" : "US", "icon" : "flag-icon-us" }
],
icon: "flag-icon-fr"
};
var helpers = {
doSelect : function(){
// Fake business rule, I.E. call a web service to get country data
var valueFromBusinessLogic = "FR";
$.observable(dataVm).setProperty("value", valueFromBusinessLogic);
}
};
$.templates("#mainTemplate").link("#container", dataVm, helpers);
})(jQuery);
<link href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
<script id="mainTemplate" type="text/x-jsrender">
<p>Selected : <span>{^{:value}}</span></p>
<p>Flag : <span data-link="class{:('flag-icon ' + icon)}"></span></p>
<select data-link='value'>
{^{for choices}}
<option value="{{:value}}">{{:label}}</option>
{{/for}}
</select>
<button data-link="{on ~doSelect}">Select from business logic</button>
</script>
<div id="container">
</div>
This is working as expected, but I can't get the icon sub property.
My value property is important and may be set from external actions (form init or button click). So I can't (at least I believe), I can't play with #index because it would put the index in the value property.

You need to decide what your selected country property is - it can be the object, the index in the choices array, or the value string. But the default binding of the select is the value.
If you keep the value string as selected country, then you can define a lookup helper to return the object:
function countryFromVal(val) {
var i = dataVm.choices.length;
while (i--) {
if (dataVm.choices[i].value === val) {
return dataVm.choices[i];
}
}
return dataVm.choices[0];
}
var helpers = {
countryFromVal: countryFromVal,
and write
<span data-link="class{:('flag-icon ' + ~countryFromVal(value).icon)}"></span>
Alternatively you can make the selected country property be the index, and use converters on the select like in this sample: http://www.jsviews.com/#link-select#selectconvert.
Or you can make it be the object itself, again using converters, like this:
(function($) {
var dataVm = {
choices: [
{ "label" : "France", "value" : "FR", "icon" : "flag-icon-fr" },
{ "label" : "Germany", "value" : "DE", "icon" : "flag-icon-de" },
{ "label" : "Brazil", "value" : "BR", "icon" : "flag-icon-br" },
{ "label" : "USA", "value" : "US", "icon" : "flag-icon-us" }
]
};
dataVm.country = dataVm.choices[1];
function countryFromVal(val) {
var i = dataVm.choices.length;
while (i--) {
if (dataVm.choices[i].value === val) {
return dataVm.choices[i];
}
}
return dataVm.choices[0];
}
function valFromCountry(country) {
return country.value;
}
$.views.converters({
fromValue: countryFromVal,
toValue: valFromCountry
});
var helpers = {
doSelect : function(){
// Fake business rule, I.E. call a web service to get country data
var valueFromBusinessLogic = "FR";
$.observable(dataVm).setProperty("country", countryFromVal(valueFromBusinessLogic));
}
};
$.templates("#mainTemplate").link("#container", dataVm, helpers);
})(jQuery);
<link href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
<script id="mainTemplate" type="text/x-jsrender">
<p>Selected : <span>{^{:country^value}}</span></p>
<p>Flag : <span data-link="class{:'flag-icon ' + country^icon}"></span></p>
<select data-link='{toValue:country:fromValue}'>
{^{for choices}}
<option value="{{:value}}">{{:label}}</option>
{{/for}}
</select>
<button data-link="{on ~doSelect}">Select from business logic</button>
</script>
<div id="container"></div>
Note the syntax country^icon - see http://www.jsviews.com/#linked-paths#deep

Related

How to Get Array Data in HTML Using Meteor JS?

I need to know about to get array data of collections using Meteor JS. I did a simple example with insert data to collections in Meteor JS as shown below :
if (Hcare_Fileds.find().count() === 0) {
var fieldData = [
{fieldName: "Hcare1",
fieldOptions: [ "Bike","Car","TV","Radio","etc"]
},
{fieldName: "Hcare2",
fieldOptions: [ "Bike1","Car1","TV1","Radio1","etc"]
},
{fieldName: "Hcare3",
fieldOptions: [ "Bike2","Car2","TV2","Radio2","etc"]
}
];
for (var i = 0; i < fieldData.length; i++)
{
var list_id = Hcare_Fileds.insert({fieldname: fieldData[i].fieldName,fieldoptions: fieldData[i].fieldOptions}
, function( error, result)
{
if ( error ) console.log ( "Error :"+error.reason ); //info about what went wrong
if ( result )
{
console.log ( "Success="+result );//the _id of new object if successful
}
});
}
}
And Access the above collection fieldoption array data sa shown below :
{{#each fieldName}}
<div class="fmenu {{isselected}}"> {{ fieldname }} </div>
<div class="foptions">
{{#if isselected}}
{{ fieldoptions }}
// Here get fieldoptions data when selected filedname as Bike,Car,Tv,Radio,etc but i need to return like as array but it returns string
{{/if}}
</div>
{{/each}}
JS Code :
if (Meteor.isClient)
{
Session.set('currentFieldName', '');
Template.main.fieldName = function ()
{
return Hcare_Fileds.find().fetch();
};
//TODO ::
Template.main.events
({
'click .fmenu': function (e,t)
{
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button"+this.fieldname);
e.preventDefault();
Session.set('currentFieldName', this.fieldname);
}
});
Template.main.isselected = function ()
{
console.log("currentFieldName");
return Session.equals("currentFieldName", this.fieldname) ? "selected" : '';
};
}
I need to get data as array not string like Bike,Car,Tv,Radio,etc. I didn't get any idea about this.So Can you please suggest me what to do?

Knockoutjs: bind dynamic iframes in foreach to parent

I am trying to bind iframe and parent window so that I can change/update an observable in either the iframe or parent window and both views will update with new value.
Here is working sample: http://jsfiddle.net/NnT78/26/
I have tweaked some sample code that I have found and have it working great as follows;
HTML:
<iframe src="http://fiddle.jshell.net/zVPF8/11/show/" data-bind="bindIframe: $data"></iframe>
But when I put the same html in a foreach bind it get an error;
HTML:
<ul data-bind="foreach: iframes">
<li>
<iframe data-bind="attr: {src: src}, bindIframe: $data"></iframe>
</li>
</ul>
Error:
Uncaught ReferenceError: Unable to parse bindings.
Bindings value: text: someProperty
Message: someProperty is not defined
Here is my Knockoutjs ViewModel code;
ko.bindingHandlers.bindIframe = {
init: function(element, valueAccessor) {
function bindIframe() {
try {
var iframeInit = element.contentWindow.initChildFrame,
iframedoc = element.contentDocument.body;
} catch(e) {
// ignored
}
if (iframeInit)
iframeInit(ko, valueAccessor());
else if (iframedoc){
ko.applyBindings(valueAccessor(), iframedoc);
}
};
bindIframe();
ko.utils.registerEventHandler(element, 'load', bindIframe);
}
};
function ViewModel() {
var self = this;
self.someProperty = ko.observable(123);
self.clickMe = function(data, event) {
self.someProperty(self.someProperty() + 1);
}
self.anotherObservableArray = ko.observableArray([
{ name: "Bungle", type: "Bear" },
{ name: "George", type: "Hippo" },
{ name: "Zippy", type: "Unknown" }
]);
self.iframes = ko.observableArray([
{ src: "http://fiddle.jshell.net/zVPF8/6/show/", type: "Bear" },
{ src: "http://fiddle.jshell.net/zVPF8/6/show/", type: "Hippo" },
{ src: "http://fiddle.jshell.net/zVPF8/6/show/", type: "Unknown" }
]);
};
// Bind outer doc
ko.applyBindings(new ViewModel());
See http://jsfiddle.net/NnT78/26/ for sample of single iframe working and dynamic iframes in foreach bind not working.
Thanks in advance!
When in a foreach binding, $data is different; it's the current item in the array. You can fix your example by changing the iframe to bind to $root instead.
<iframe data-bind="attr: {src: src}, bindIframe: $root"></iframe>
http://jsfiddle.net/mbest/NnT78/29/

preload the selected values of a kendo multiselect that using a server bound data source and templated tags

I have a kendo multiselect as follows.
$("#tags").kendoMultiSelect({
change: onChange,
dataSource: {
transport: {
prefix: "",
read: {
url: "/OpsManager/Api/Activity/SearchResourcesTagged",
data: getSubmitData
}
},
serverFiltering: true,
filter: [],
schema: { errors: "Errors" }
},
itemTemplate: $('#resourceItemTemplate').html(),
tagTemplate: $('#resourceTagTemplate').html(),
dataValueField: "k",
value: [{"k":"[109]","n":"All Open Alerts","icon":"!","all":105}]
});
with the following templates:
<script id="resourceItemTemplate" type="text/x-kendo-template">
<span data-icon="#:data.icon#" class="#: data.s || '' #"> #:data.n #</span>
# if (data.d) { #
<div class="details">#: data.d #</div>
# } #
# if (data.details) { #
<div class="details k-state-disabled">
# for (var v in data.details) {
var t = typeof data.details[v];
if (t != "object" && t != "function" && v != "uid") { #
<div class="k-button">#: v #: #: data.details[v] #</div>
# } } #
</div>
# } #
</script>
<script id="resourceTagTemplate" type="text/x-kendo-template">
<span data-icon="#:data.icon#" class="tag-content #: data.s || '' #"> #:data.n #</span>
</script>
<select id="tags" multiple="multiple" name="tags"></select>
I'm trying to preload a specific selection and I can't seem to get it to work.
selection:
[{"k":"[109]","n":"All Open Alerts","icon":"!","all":105}]
I've put the initialized value in place according to their documentation and looking the multiselect object up inside the browser I see the passed in object inside _initialValues but I don't see anything inside _dataItems or in the tag list on the ui.
Any clues how to get this working?
Thanks to #OnaBai,
The problem is a difference in expected content of the datasources. The datasource originally loaded is not looking for "[109]" but rather "some string query" and then provides a specific list around that search. Thus I need to initialize a fake datasource for the control and then immediately switch out the data source for the dynamic one.
$("#tags").kendoMultiSelect({
change: onChange,
dataSource: {
transport : {
read: function (op) {
op.success([{"k":"[109]","n":"All Open Alerts","icon":"!","all":105}]);
}
}
},
itemTemplate: $('#resourceItemTemplate').html(),
tagTemplate: $('#resourceTagTemplate').html(),
dataValueField: "k",
value: ["[109]"]
});
$("#tags").data("kendoMultiSelect").setDataSource({
transport: {
read: {
url: "OpsManager/Api/Activity/SearchResourcesTagged",
data: getSubmitData
}
},
serverFiltering: true,
filter: [],
schema: { errors: "Errors" }
});
after that it works exactly like expected.
Two problems:
Define value in multiselect and not in dataSource.
Set value to an array with the list of key values that you want to initially load (in your case just "[109]").
Something like:
$("#tags").kendoMultiSelect({
change: onChange,
dataSource: {
transport: {
prefix: "",
read: {
url: "/OpsManager/Api/Activity/SearchResourcesTagged",
data: getSubmitData
}
},
serverFiltering: true,
filter: [],
schema: { errors: "Errors" }
},
itemTemplate: $('#resourceItemTemplate').html(),
tagTemplate: $('#resourceTagTemplate').html(),
dataValueField: "k",
value: ["[109]"]
});
Example in here

adding button returns [object][object] in EXTJS

Am having a controller which basically calls a message window that is displayed for a few seconds. Am trying to add a button to this message window, but its returning [object][object].
Controller
success : function(response) {
this.mWin = Ext.create('App.view.GenMessage');
this.mWin.addMessage(true, LANG.SUCT, LANG.SUCTxt1);
}
View
Ext.define('App.view.GenMessage', {
extend : 'Ext.panel.Panel',
alias : 'widget.genmessage',
initComponent : function() {
this.msgCt = App.genMsgCt
this.msgCt.setWidth(300);
},
addMessage : function(status, title, msg) {
if (status == false) {
delay = 3000;
} else {
delay = 2000;
}
Ext.DomHelper.append(this.msgCt, {
html : this.buildMessageBox(status, title, msg)
}, true).slideIn('t').pause(delay).ghost("t", {
remove : false
});
},
/*
* buildMessageBox
*/
buildMessageBox : function(status, title, msg) {
console.log('buildMesssage');
switch (status) {
case true :
var icon = GENHTML.tick;
break;
case false :
var icon = GENHTML.warning;
break;
}
return ['<div class="genMsgDiv">', icon,
'<div class="genMsgHd leftMargin">', title,
'</div><div class="H3 leftMargin">', msg,
'</div></div>'].join('');
}
What i did was declare a button like
var button={
id: 'button1',
text :'Button1'
}
and then add to the div class mentioned above and return
['<div class="genMsgDiv">', button].join();
But, what i see in the screen is [object][object] in place of the button.
Could anyone please tell me what am doing wrong here. Is this the correct way to add the button
EDIT
Since we cannot add a button to a div, i tried doing
var config = Ext.create(Ext.panel.Panel, {
itemId : 'GENMSGPANEL',
height : 150,
cls : 'msg effect1',
border : false,
html : '<div class="genMsgDiv">' + icon +
'<div class="genMsgHd leftMargin">'+ title +
'</div><div class="H3 leftMargin">'+ msg +
'</div></div>',
items : [{
xtype : 'panel',
//cls : 'winTitle',
}, {
xtype : 'form',
itemId : 'GENMSGFORM',
border : false,
title : '',
buttonAlign : 'center',
fieldDefaults : {
msgTarget : 'side',
labelWidth : 110,
size : 30
},
buttons : [{
text : LANG.BTYES,
iconCls : 'icon-tick-tb',
iconAlign : 'right',
cls : 'tip-btn',
action : 'genDelete',
id : 'BTYES'
}, {
text : LANG.BTNO,
iconCls : 'icon-cross-tb',
iconAlign : 'right',
cls : 'tip-btn',
action : 'notDelete',
id : 'BTNO'
}]
}]
});
return config;
But, even this did not return anything
The answer is simple: You cannot add a ExtJS Button into the html config property of a component. This one is just for plain html. ExtJS objects belongs into the items array.
Decide to place your html content into a box (xtype for component) and add this to the items array. Then you can add your button. Don't use the html at all in your case.
You may change/set any required classes. Please note that I haven't check the way you manipulate the DOM.
// you may use a layout to align them
items : [
{
xtype: 'box',
cls : 'msg effect1',
html : '<div class="genMsgDiv">' + icon +
'<div class="genMsgHd leftMargin">'+ title +
'</div><div class="H3 leftMargin">'+ msg +
'</div></div>'
},
{
xtype : 'panel',
//cls : 'winTitle',
},
...

onClick function of button that is in a datagrid row - extjs

I have put a button on a dataGrid with the following code
column is;
var avaliableAction = {
header : "Action",
width : 120,
sortable : true,
align : "left",
dataIndex : 'status',
renderer : statusRenderer
};
data grid is;
var mainJobsGrid = new Ext.grid.GridPanel({
store : jobsStore,
columns : [ avaliableAction ],
viewConfig : {
forcefit : true
},
title : 'Data Mart Jobs',
height : 198,
width : 540,
frame : true
});
renderer is;
function statusRenderer(value, id, r) {
var START_ICON = '/etlscheduler/resources/images/start-icon.png';
var STOP_ICON = '/etlscheduler/resources/images/stop-icon.png';
if (value == "STOPPED") {
return "<input type='button' class='btnStart' onClick='doStart(); '>";
} else if (value == "RUNNING" || value == "WAITING") {
return "<input type='button' class='btnStop' onClick='doStop();'>";
}
};
and
function doStop() { ... }
function doStart() { ... }
The problem is that when I click the button exception occurs as "doStop is not defined"
seems like you need to define the function
function doStop() { ... }
I faced the same problem, and it wasn't a typo! i have noticed that the implementation of the called function works only if it was outside the "Ext.onReady(function(){}".
If someone faces the same problem, i have solved it through writing the function as following:
Ext.the_function = function(){...}
instead of :
var the_function = function(){...}
This would fix the problem and it will work wherever you put it!

Resources