I have to string concatenate value from resource file with KO observable string.
Here is what I tried
But I'm getting error message
Message: Office is not defined
at text (eval at parseBindingsString (knockout-3.4.0.js:68), :3:82)
at update (knockout-3.4.0.js:98)
at function.a.B.i (knockout-3.4.0.js:72)
at Function.Pc (knockout-3.4.0.js:51)
at Function.Qc (knockout-3.4.0.js:51)
at Function.aa (knockout-3.4.0.js:50)
at Object.a.m.a.B (knockout-3.4.0.js:49)
at knockout-3.4.0.js:72
at Object.q (knockout-3.4.0.js:11)
at m (knockout-3.4.0.js:71)
"Office is not defined" here Office is value I get from resource file for #Resources.Office.
can you pass your resource file into the viewmodel? then you should have access to it. run snippet below.
function model(Resources) {
var self = this;
this.Resources = ko.observable(Resources);
this.foo = ko.observable({
WorkPhone: true,
CellPhone: false
});
}
var Resources = {
'Office': '222-2222',
'OfficeMobile': '333-3333',
'Home': '444-4444'
}
var mymodel = new model(Resources);
$(document).ready(function() {
ko.applyBindings(mymodel);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="with: foo">
<span data-bind="text: $data.WorkPhone ?
'Office: ' + $parent.Resources().Office +
' ,Office Mobile: ' + $parent.Resources().OfficeMobile
: 'Home: ' + $parent.Resources().Home"></span>
</div>
although I agree with Jose that a computed or pure computed is probably a better way to go.
Related
I have a HTML file that uses some JScript that I found online and would like it to incorporate it into a simple page for internal use that can be used to quickly look up information.
The page would present the data from a JSON file that is stored on the server.
I can add the JSON data directly to the HTML file, but would like a file that we can export from time to time in-place with the new data and now have to manually edit the HTML files directly.
So far I have this HTML file:
<html>
<head>
<script type='text/javascript'>//<![CDATA[
$(function(){
var a = ['https://url.com/data.json'];
jQuery('#search-json-submit').click(function() {
jQuery('#search-output').html('');
var search_query = jQuery('#search-json-input').val();
var search_query_regex = new RegExp(".*"+search_query+".*", "g");
jQuery.each(a, function(k, v) {
if(v['name'].match(search_query_regex) ||
v['id'].match(search_query_regex) ||
v['location'].match(search_query_regex)) {
jQuery('#search-output').append('<li>Search results found in: '+'{ name: "'+v['name']+'", id: "'+v['id']+'", location: "'+v['location']+'" } </li>');
}
});
});
});//]]>
</script>
</head>
<body>
<input type="text" id="search-json-input" />
<input type="button" id="search-json-submit" value="search" />
<h4>Search Results</h4>
<ol id="search-output">
</ol>
</body>
</html>
My JSON file is the following text:
{"name":"mynewname", "id" : "t2", "location" : "India"},
{"name":"mynewname1", "id" : "t21", "location" : "China"},
I am not sure what I am doing wrong to link the variable a to the JSON file URL to search.
I had a look at another page and it linked the JSON file using
$.getJSON('https://url.com/data.json')
but I can't get that to work either.
The original a variable for this example is:
var a =[
{"name":"mynewname", "id" : "t2", "location" : "India"},
{"name":"mynewname1", "id" : "t21", "location" : "China"},
];
Once I get the search function to work, I can then format it properly and find a more suitable solution in the long term. For now I would like to just kick start this and get it up and running.
Try
$(function () {
jQuery.getJSON("data.json", function (a) {
jQuery('#search-json-submit').click(function () {
jQuery('#search-output').html('');
var search_query = jQuery('#search-json-input').val();
var search_query_regex = new RegExp(".*" + search_query + ".*", "g");
jQuery.each(a, function (k, v) {
if (v['name'].match(search_query_regex) || v['id'].match(search_query_regex) || v['location'].match(search_query_regex)) {
jQuery('#search-output').append('<li>Search results found in: ' + '{ name: "' + v['name'] + '", id: "' + v['id'] + '", location: "' + v['location'] + '" } </li>');
}
});
})
});
});
Make sure that data.json is located on same server(domain) as your js/html(cross origin policy).
Update: http://jsfiddle.net/m7jocxwh/1/
I have the following script , that is being used inside multiple views:-
$("#ChoiceTag, #ChoiceName").each(function () {
$(this).change(function () {
if ($("#ChoiceName").prop("checked")) {
$.getJSON("#Url.Content("~/Firewall/LoadCSName")",
function (CSData) {
var select = $("#GeneralCSID");
select.empty();
select.append($('<option/>', {
value: "",
text: "Select Name..."
}));
$.each(CSData, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
select.val('#Model.CSIT360ID');
});
});
}
the script is exactly the same for all the views except for the controller name inside the following statement:-
$.getJSON("#Url.Content("~/Firewall/LoadCSName")",
so i am looking to move the above script and add it inside a separate .js file, and then reference this script , but i have the following two question:-
if i move the script to the script folder i need to dynamically reference the current controller name to build the URL, so is this possible
can i still reference the viewbag as i am currently doing ..
Thanks
If you move your Javascript into an external file you can't use your Razor syntax. Therefore, #Url.Content("~/Firewall/LoadCSName") will not resolve.
To overcome this add this to your view
<script type="text/javascript"> var AppPath = '#Url.Content("~/")'</script>
and reference it in your script like this
$.getJSON(AppPath + "Controller/Action")
Regarding the viewbag. Just put the viewbags value in a variable as shown above and your external file can reference it.
Hope this helps
Update
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script type="text/javascript">
var AppPath = '#Url.Content("~/")';
var SomeValue = '#Model.CSIT360ID';
var ControllerName = "Firewall/LoadCSName";
</script>
<!--Move this to an external File-->
<script type="text/javascript">
$("#ChoiceTag, #ChoiceName").each(function () {
$(this).change(function() {
if ($("#ChoiceName").prop("checked")) {
$.getJSON(AppPath + ViewBagValue), function(CSData) {
var select = $("#GeneralCSID");
select.empty();
select.append($('<option/>', {
value: "",
text: "Select Name..."
}));
$.each(CSData, function(index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
select.val(SomeValue);
});
//end each
});
}
});
</script>
</body>
</html>
Update 2
This is how you could reference the controller in the url.content
<script type="text/javascript">
var AppPath = '#Url.Content("~/" + HttpContext.Current.Request.RequestContext.RouteData.Values["controller"])'
</script>
you can get the controller name this way:
#{
string controllerName = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
}
To access controller name from view use
#{
ViewContext.RouteData.Values["controller"].ToString();
}
To access controller instance one can use as follow
#{
(HomeController)ViewContext.Controller
}
One (slightly hacky) to make the current controller name accessible to JS would be to burn it into a global or namespaced variable assignment in the layout.
<script>
var app = window.app || {}
app.currentController = "#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString().toLower()";
</script>
Alternatively, a common way I work is to add classnames of the current controller and action to the body tag, to assist in DOM based routing in any javascript.
I'm trying to use grunt-contrib-jst to compile my underscore templates, but it seems to not be rendering / preserving the variables properly. Here's what a template looks like normally:
<script id="header-template" type="text/template">
<h4><%= subhead %></h4>
<h1><span class="head-text"><%= head %></span>
<span class="subtext"><%= subtext %></span>
</h1>
<p></p>
</script>
and here's what gets rendered via grunt:
this["JST"] = this["JST"] || {};
this["JST"]["templates/header.html"] = function(obj) {
obj || (obj = {});
var __t, __p = '', __e = _.escape;
with (obj) {
__p += '<h4>' +
((__t = ( subhead )) == null ? '' : __t) +
'</h4>\n<h1><span class="head-text">' +
((__t = ( head )) == null ? '' : __t) +
'</span>\n <span class="subtext">' +
((__t = ( subtext )) == null ? '' : __t) +
'</span>\n</h1>\n<p></p>';
}
return __p
};
Here's how I set up my grunt task:
jst: {
compile: {
files: {
"scripts/templates/all.js": ["templates/*.html"]
}
}
}
and when I attempt to utilize the template:
var app = app || {};
app.HeaderView = Backbone.View.extend({
el: '#header-container',
//template: _.template( $( '#header-template' ).html() ),
template: JST['templates/header.html'](), //http://stackoverflow.com/questions/8366733/external-template-in-underscore
initialize: function( templateContent ) {
this.render(templateContent);
},
render: function(templateContent) {
this.$el.html(this.template(templateContent));
return this;
}
});
I get this error:
Uncaught ReferenceError: subhead is not defined
Any idea what's wrong and how to maintain the formatting of my original templates?
You say that you are
[...] trying to use grunt-contrib-jst to compile my underscore templates
That's exactly what's happening. If you look at the _.template docs, you'll see this:
The source property is available on the compiled template function for easy precompilation.
If you do this with that <script>:
var t = _.template($('#header-template').html());
console.log(t.source);
you'll see that ugly function in the console.
Demo: http://jsfiddle.net/ambiguous/WjNGC/
So your JST task is simply compiling your templates using _.template and then dump the compiled template function's source attribute to a file; then, when the browser loads that JavaScript file, you get the compiled template back.
The result is that you can say this:
var html = JST['templates/header.html'](data);
and get the filled-in template in html without having to compile the template in the browser.
I am getting this and a couple other weird error messages on my main ASP MVC 3 layout page.
I am using the following scripts
<script src="#Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-1.8.3.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/typeahead.js")" type="text/javascript"></script>
And trying to get the typeahead.js to work in our nav bar. Below is the code I currently have on my machine. I had this working at one point in time, however after a sync up with a coworker the typeahead search does not work anymore and I haven't been able to track down the issue.
The first line in the code below gives the following error
Uncaught TypeError: Cannot read property 'Constructor' of undefined
If I comment out the protoype.blur function, however, I then get this error
Uncaught TypeError: Object [object Object] has no method 'typeahead'
Which points to the $('.AgentSearch .typeahead).typeahead function. Been stuck on this for hours, any help would be greatly appreciated. Thanks
// Workaround for bug in mouse item selection
$.fn.typeahead.Constructor.prototype.blur = function () {
var that = this;
setTimeout(function () { that.hide() }, 250);
};
$('.AgentSearch').typeahead({
source: function (term, process) {
var url = '#Url.Action("GetAgents", "Agent")';
var agents = [];
map = {};
return ($.getJSON(url, { term: term }, function (data) {
$.each(data, function (i, item) {
map[item.Name] = item;
agents.push(item.Name);
});
process(agents);
}));
},
highlighter: function (item) {
var p = map[item];
var display = ''
+ "<div class='typeahead_wrapper'>"
+ "<div class='typeahead_labels'>"
+ "<div class='typeahead_primary'>" + p.Name + "</div>"
+ "<div class='typeahead_third'><i>LastFour:</i> " + p.LastFour + "</div>"
+ "</div>"
+ "</div>";
return display;
},
updater: function (item) {
window.location.href = ("/Monet/Agent/Details/" + map[item].SymetraNumber);
}
});
Here is the search box I'm binding this to
<form class="navbar-search pull-left">
<input type="text" name="names" value="" id="AgentSearch" class="search-query" data-provide="typeahead" placeholder=" Agent Search"/>
</form>
EDIT
Here are the script tags as they're rendered by the browser
<script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery-1.8.3.js" type="text/javascript"></script>
<script src="/Scripts/jquery-ui.js" type="text/javascript"></script>
<script src="/Scripts/typeahead.js" type="text/javascript"></script>
It looks like typeahead is not defined.
If you're trying to extend typeahead, this article may help:
Extend the bootstrap-typeahead in order to take an object instead of a string
$.fn will always return an object ('[]'), this is why the error change when you comment-out .prototype.blur, but they're both indicating 'typeahead' doesn't exist.
Just a guess, but it could be a synchronicity issue where your code is running before the library loads.
I might be missing something really simple but can anyone point out where i'm doing wrong here?
many thanks in advance.
<div data-bind="foreach: agencies">
<div data-bind="text:name"></div>
<div data-bind="text:email"></div>
<button data-bind="click: removeAgency">remove</button>
</div>
<script type="text/javascript">
var agency = [{
name : ko.observable('a'),
email : ko.observable('b')
}, {
name: ko.observable('c'),
email: ko.observable('d')
}];
var vm = {
agencies: ko.observableArray(agency),
removeAgency: function(agency) {
this.agencies.remove(agency);
}
};
ko.applyBindings(vm);
</script>
this is the error i get: Uncaught Error: Unable to parse bindings.
Message: ReferenceError: removeAgency is not defined;
Bindings value: click: removeAgency
You are binding to an agency in that html, but your method is on your viewmodel. Try something like:
<button data-bind="click: $parent.removeAgency">remove</button>
You might need to re-jig your vm to get the scope correct:
var ViewModel = function(){
var self = this;
self.agencies = ko.observableArray(agency),
self.removeAgency = function(agency) {
self.agencies.remove(agency);
}
};
var vm = new ViewModel();
I still get confused at times with scope, I have to admit, but give this a try and see what happens.
Working example:
http://jsfiddle.net/marko4286/7RDc3/2034/
Read documentation http://knockoutjs.com/documentation/foreach-binding.html