I am investigating what is possible with i18next localization library.
Right now I have the following code (full Fiddle is here):
HTML
<div data-i18n="title"></div>
<input placeholder="Hello" value="name">
<div class="holder"></div>
<button class="lang" data-lang="en">Eng</button>
<button class="lang" data-lang="ch">Chi</button>
JS
$(document).ready(function () {
i18n.init({
"lng": 'en',
"resStore": resources,
"fallbackLng" : 'en'
}, function (t) {
$(document).i18n();
});
$('.lang').click(function () {
var lang = $(this).attr('data-lang');
i18n.init({
lng: lang
}, function (t) {
$(document).i18n();
});
});
});
It translates all text elements, but the problem is that I can not translate custom attributes. For example text inside the div is translated, but I can not understand how can I translate custom attributes like placeholder and value.
Another problem is with my way of translation. Whenever a button Chi, Eng is clicked, I am initializing the translation (but I am not sure this is a correct way). Edit I think I found how to solve this problem (I need to use setLng): i18n.setLng(lang, function(t) { ... })
After asking i18next creator this question directly, I received the following reply: all I need is to put my custom attribute in front of the translation element. Here is an example:
<div data-i18n="[title]titleTransl"></div>
<input data-i18n="[placeholder]placeTransl" value="name">
If multiple attributes are needed, separate them by a ;.
I learned 2 things by this:
I have to read better documentation.
118next's creator is really helpful (this is a thank you remark for him).
For me the following worked
<input data-i18n="[placeholder]placeTransl" value="name">
So just enter the attribute's name between [] and then the translation.
Consider calling
$('body').i18n()
inside .done() function. You should tell where to look for localizer.
This will work without having to call [placeholders] in the data-i18n attribute.
Related
I have these lines of code:
<span
class="close-modal"
onclick="#Html.Action("SaveNotes", "CallCenter", new { activityId = item.callIdKey, noteText = "test1" })">
×
</span>
Notes: <br />
<textarea name="paragraph_text" rows="5" style="width:90%">
#item.NoteText
</textarea>
I would like to replace test1 from the noteText route variable and instead change it to whatever the value in the <textarea> tag is.
Is there an elegant way of doing this without writing a giant block of jQuery code?
#Html.Action() renders a partial view as an HTML string during page processing (on the server side). It doesn't exist any more in the markup, once the page is sent to the browser. You can't do what you are trying to do this way. At the very least, I'm sure you don't want to render a partial view inside the onclick event of your <span> tag.
Why not instead use an HTML helper for the <textarea> tag? Then you can get whatever value the user typed into it on the server code. You'll want to make the form post itself back to the server on the close-modal element:
<span class="close-modal" onclick="$('form').submit()">×</span>
<form method="post" action="#Url.Action("SaveNotes", "CallCenter", new { activityId=item.callIdKey }">
Notes: <br />
#Html.TextArea("noteText", item.NoteText, new { rows="5", style="width:90%" })
</form>
This assumes you have jQuery already (a common assumption with ASP.NET). You may not need the <form> tags if you already have a form on your page.
A #gunr2171 notes in the comments, the only way to dynamically update a link once it's been rendered to the browser is via some form of client-side scripting, typically JavaScript. In your case, I'd recommend doing something like this:
<span
class="close-modal"
data-href-template="#Url.Action("SaveNotes", "CallCenter", new {activityId = item.callIdKey, noteText="{note}"})"
>
×
</span>
Note: As #HBlackorby notes in his answer, you shouldn't be using #Html.Action() here; I assume you meant #Url.Action().
This way, your JavaScript has a template (data-href-template) that it can work against with a clearly defined token ({note}) to replace, instead of needing to parse the URL in order to identify where the previously replaced text is. Otherwise, you potentially end up in a scenario where you type e.g. CallCenter into your <textarea /> and it's now an ambiguous reference that you can't just blindly replace. Or, worse, you type 'a' and it's really ambiguous.
If you are already using jQuery on your site, the actual replacement might be done using something along the lines of:
$(document).ready(function () {
$('span.close-modal').click(function() {
var noteInput = $('textarea[name="paragraph_text"]');
var encodedNote = encodeURI(noteInput.text());
var template = $(this).data("href-template");
var targetUrl = template.replace("{note}", encodedNote);
window.location.href = targetUrl;
});
});
You can also do this without jQuery, obviously—and should if you're not already depending on it. The point is to illustrate that this doesn't necessarily need to be a "giant block of jQuery code". In fact, this could be done in just a few lines—and probably should be. I deliberately broke it out into multiple steps and variables for the sake of readability.
I have a HTML page where a user is able to edit a HTML resource (using ACE Editor). Within this HTML source, there is a <script>-tag, which does some pretty basic stuff.
Is there any elegant solution to parse the script tag in order to (e.g.) evaluate the variables used within the script tag? For "normal" tags I use parseHTML() to have the html as a jQuery object.
From this example, I would like to retrieve the value of $myVal (which is "f00") and write it to #myLabel:
<textarea id="myScript" rows="5" readonly>
<script>
$myVal = "f00";
</script>
</textarea>
<label id="myLabel">Hello</label>
$(function(){
$scriptVar = $('#myScript').text;
// parse the $scriptVar
// retrieve the value of, $myVal, write it to #myLabel
//$myParsedValue = ???
//$('#myLabel').text('bar!');
});
And here is the fiddle: https://jsfiddle.net/stepdown/jqcut0sn/
Is this possible at all? I don't really care about vanilla js, jQuery, regex or maybe even an external library for that purpose.
Thanks to #JeremyThille, who pointed me to the right direction. I found out, what I want to achieve is possible through jQuerys $.globalEval() - see the official documentation.
Basically what globalEval() does: it runs the script which is written in the <textarea> and makes the variables / functions globally accessible.
IMPORTANT: this implies, that syntax errors (etc) by the user will break the evaluation, and sequential functionality could be flawed. Also, the new variables are GLOBAL, so basically a user could rewrite scripts on the hosting page. (In my case both problems are of minor importance, since this is an internal application for trained users - they also have syntax highlighting through the amazing ACE editor. But I wanted to make sure to point it out. Also, there are several articles regarding the risks/ouch-moments when using eval()...)
I updated the fiddle to achieve what I wanted: https://jsfiddle.net/stepdown/Lxz7q6uv/
HTML:
<textarea id="myScript" rows="5" readonly>
$myVal = "f00";
</textarea>
<hr />
<label id="myLabel">Hello</label>
Script:
$(function(){
var myScriptContent = $('#myScript').text();
$.globalEval(myScriptContent);
console.log($myVal);
$('#myLabel').text($myVal);
});
I am experiencing odd behavior when data linking an object to a form that led me to re-question what exactly is being data bound?
Basically I have a form that creates new Companies as well as updates them. The actual creation/update is done via ajax, which is why I am using the same form for both purposes. In the case when I have to create a company, everything works as I expect. However when I have to update a company, things don't work like how I expect them to. Please have a look at the following code.
Here is my sample Form HTML:
<div id="result"></div>
<script type="text/x-jsrender" id="CompanyFormTemplate">
<form>
<input type="text" data-link="Company.Name" />
</form>
</script>
Here is my Javascript code:
var app = new CompanyFormContext();
function CompanyFormContext() {
this.Company = {
Name: ''
};
this.setCompany = function (company) {
if (company) {
$.observable(this).setProperty('Company', company);
}
};
};
$(function () {
initPage();
...
if (...) {
// we need to update company information
app.setCompany({ Name: 'Company ABC' });
}
});
function initPage() {
var template = $.templates('#CompanyFormTemplate');
template.link("#result", app);
}
Instead of the form input showing 'Company ABC', it is empty. However if I enter anything in it, then the Company.Name value does change! But while I want the input to data bind to Name property of my Company object, I also want it to be aware of any changes made to the (parent) Company object and update it's data binding to it's Name property accordingly.
So my question is how should I change the way I am writing this code so that I can achieve a data bound both on the root object as well as the property?
The issue you were having was because in your scenario, you have paths like Company.Name for which you want to data-link to changes not only of the leaf property but also to changes involving replacing objects higher up in the path (in this case the Company).
For that you need to use the syntax data-link="Company^Path".
See the section Paths: leaf changes or deep changes in this documentation topic:
http://www.jsviews.com/#observe#deep.
See also the examples such as Example: JsViews with plain objects and array in this topic: http://www.jsviews.com/#explore/objectsorvm.
Here is an update of your jsfiddle, using that syntax: https://jsfiddle.net/msd5oov9/2/.
BTW, FWIW, in your fix using {^{for}} you didn't have to use a second template - you could alternatively have written:
<form class="form-horizontal">
{^{for Company}}
...
<input type="text" data-link="Name" />
{{/for}}
</form>
To respond also to your follow-up question in your comment below, you can associate any 'block' tag with a template. Using tmpl=... on the tag means you have decided to separate what would have been the block content into a separate re-usable template. (A 'partial', if you will). The data context for that template will be the same as it would have been within the block.
So specifically, {{include}} {{if}} and {{else}} tags do not move the data context, but {{for}} and {{props}} do. With custom tags you can decide...
So in your case you could use either {^{for Company tmpl=.../}} or {{include tmpl=.../}} but in the second case your other template that you reference would use <input type="text" data-link="Company^Name" /> rather than <input type="text" data-link="Name" />.
Here are some relevant links:
http://www.jsviews.com/#samples/jsr/composition/tmpl
http://www.jsviews.com/#includetag
http://www.jsviews.com/#fortag
I discovered one way to achieve this. It might seem complex at first but it will make sense once you understand it properly.
(PS: I wish there was a sample like this. I might just blog about it.)
HTML Markup:
<script type="text/x-jsrender" id="CompanyFormTemplate">
<form>
{^{for Company tmpl="#CompanyDetailsTemplate" /}
</form>
</script>
<script type="text/x-jsrender" id="CompanyDetailsTemplate">
<input type="text" data-link="Name" />
</script>
Javascript: No changes needed from code above.
Okay so as I said, the solution might look complicated but it turns out all I really had to do was to set up data binding first on the Company object, and then to it's property objects. I wonder if there is a more elegant solution (i.e. one in which all of this can be achieved in a single template) however this solution ensures that data-binding is happening both on the parent object as well as its' properties.
I have posted a JsFiddle for this solution, so if anyone comes across this problem and wants to understand how this solution would work for their particular problem, they will be able to play with a working solution.
What's the proper way to go about it. I need it to work like in the example below.
<input type="button" value="Resume" onclick="window.location = '/Test?testid=#(ViewBag.TestID)'" />
I absolutely support Zabavsky's comment that you should use an ActionLink for this specific example in order to have semantically correct markup.
But since you asked:
Mixing razor syntax with Javascript in views
Never do that.
In your view you should have only markup:
<input type="button" value="Resume" id="myButton" data-url="#Url.Action("Test", new { testid = ViewBag.TestID })" />
and javascript (IN A SEPARATE FILE) where you could work with this markup and unobtrusively enhance it:
$(function() {
$('#myButton').click(function() {
window.location.href = $(this).data('url');
});
});
Of course if the user has javascript disabled your web application is completely busted. That's why you should always write semantically correct markup. In this case that would be to use an anchor because in HTML buttons are used to submit forms, anchors are used to redirect to some other location (which is exactly what you are trying to achieve in this specific case).
I would, as Zabavsky said, use an ActionLink for this:
Something like this:
#Html.ActionLink("Resume", "Test", new { testid = ViewBag.TestID })
There are quite a few overrides for actionlink, so you need to pick the one which fits your needs.
The one above output an a href with the text 'Resume' going to action 'Test' on the current controller, passing a routevalue of testid = ViewBag.TestID
You can do it like:
<html><head><script>function newDoc() { window.location.assign("http://www.abc.com") }</script></head><body><input type="button" value="Load new document" onclick="newDoc()"></body></html>
Hope it will help. Thanks.
Well, what you wrote is valid.
You may have VS underline your code in red cause it think you have a js error due to the '' string not ended... but if you run it, it works.
To avoid red underline, you could do :
#{string js = "window.location = '/Test?testid="+ViewBag.TestID+" '";}
<input type="button" value="Resume" onclick="#js" />
Is it alright to define and use custom tags? (that will not conflict with future html tags) - while replacing/rendering those by changing outerHTML??
I created a demo below and it seems to work fine
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<script type="text/javascript" src="jquery.min.js"></script>
</head>
<body>
<div id="customtags">
<c-TextField name="Username" ></c-TextField> <br/>
<c-NameField name="name" id="c-NameField"></c-NameField> <br/>
<c-TextArea name="description" ></c-TextArea> <br/>
<blahblah c-t="d"></blahblah>
</div>
</body>
<script>
/* Code below to replace the cspa's with the actual html -- woaah it works well */
function ReplaceCustomTags() {
// cspa is a random term-- doesn;t mean anything really
var grs = $("*");
$.each(grs, function(index, value) {
var tg = value.tagName.toLowerCase();
if(tg.indexOf("c-")==0) {
console.log(index);
console.log(value);
var obj = $(value);
var newhtml;
if(tg=="c-textfield") {
newhtml= '<input type="text" value="'+obj.attr('name')+'"></input>';
} else if(tg=="c-namefield") {
newhtml= '<input type="text" value="FirstName"></input><input type="text" value="LastName"></input>';
} else if(tg=="c-textarea") {
newhtml= '<textarea cols="20" rows="3">Some description from model</textarea>';
}
obj.context.outerHTML = newhtml;
}
z = obj;
});
}
if(typeof(console)=='undefined' || console==null) { console={}; console.log=function(){}}
$(document).ready(ReplaceCustomTags);
</script>
</html>
Update to the question:
Let me explain a bit further on this. Please assume that JavaScript is enabled on the browser - i.e application is not supposed to run without javascript.
I have seen libraries that use custom attributes to define custom behavior in specified tags. For example Angular.js heavily uses custom attributes. (It also has examples on custom-tags). Although my question is not from a technical strategy perspective - I fail to understand why it would strategically cause problems in scalability/maintainability of the code.
Per me code like <ns:contact .....> is more readable than something like <div custom_type="contact" ....> . The only difference is that custom tags are ignored and not rendered, while the div type gets rendered by the browser
Angular.js does show a custom-tag example (pane/tab). In my example above I am using outerHTML to replace these custom tags - whilst I donot see such code in the libraries - Am I doing something shortsighted and wrong by using outerHTML to replace custom-tags?
I can't think of a reason why you'd want to do this.
What would you think if you had to work on a project written by someone else who ignored all common practices and conventions? What would happen if they were no longer at the company to find out why they did something a certain way?
The fact that you have to just go through with JavaScript to make it work at all should be a giant red flag. Unless you have a VERY good reason to, do yourself a favor and use the preexisting tags. Six months from now, are you going to remember why you did things that way?
It may well work, but it's probably not a good idea. Screen readers and search engines may have a hard/impossible time reading your page, since they may not interpret the JavaScript. While I can see the point, it's probably better to use this template to develop with, then "bake" it to HTML before putting it on the server.