I am using the tokeninput control found here at http://loopj.com/jquery-tokeninput/ - its quite popular I believe.
I have the following code that fills the input box nicely with author names - but I want to prepopulate the control with values found in the database when the user is in an EDIT session i.e. to find authors that have been found for that record already (looks something like this):
Here's the code:
$("#authorlist").tokenInput('/author/getauthors/', {
hintText: "Enter surname",
searchingText: "Searching...",
preventDuplicates: true,
allowCustomEntry: true,
highlightDuplicates: false,
tokenDelimiter: "*",
theme: "facebook"
// prePopulate: [{"id": 5016, "name": "Test 1" }]
});
Obviously this already gets a full list of authors (/author/getauthors/) - but it needs to prepopulate from that list too, with authors already found that record - and thats the bit I can't seem to figure out.
I can see that that you can use prePopulate in the javascript (I've commented it out) and I have the found author values in my Edit.cshtml i.e.
#foreach(var item in Model.AUTHORs.Select(model => new { model} ))
{
<div type="hidden" id="authorHidden" > #item.model.FULL_NAME</div>
}
So it's just a case of putting those values in some kind of json format and getting the tokeninput control to populate them ready for when the form is loaded and shown to the user.
Other code for displaying the tokeninput control in Edit.cshtml is:
<div class="editor-label">Authors</div>
<div class="authors">
<div class="editor-field">
<input type="text" id="authorlist" name="tiAuthors" />
</div>
</div>
Any help or pointers are much appreciated.
You could use an HTML5 data-* attribute on your input inside the view to put the list of authors that you want to be prepopulated:
<input type="text" id="authorlist" name="tiAuthors" data-authors="#Json.Encode(Model.AUTHORs.Select(a => new { id = a.AuthorId, name = a.AuthorName })))" />
and then:
$('#authorlist').tokenInput('/author/getauthors/', {
hintText: 'Enter surname',
searchingText: 'Searching...',
preventDuplicates: true,
allowCustomEntry: true,
highlightDuplicates: false,
tokenDelimiter: '*',
theme: 'facebook',
prePopulate: $('#authorlist').data('authors')
});
Related
I'm editing a custom theme in BigCommerce, and I'm working on the product options section of the code on a product page. This is for a product page for a product with multiple options. A default parent SKU is shown above the options. Upon choosing an option, the new, final SKU gets populated above. The handlebar code to show that SKU is {{product.sku}}.
I've found that customers get confused and don't realize there are other SKUs available if they just choose the right option, so I want to show the SKU within the label of the option.
Here is the part of the code I'm targeting (from set-rectangle.html):
<div class="form-field" data-product-attribute="set-rectangle">
<label class="form-label form-label--alternate form-label--inlineSmall">
{{this.display_name}}:
<span data-option-value></span>
{{#if required}}
<small>{{lang 'common.required'}}</small>
{{/if}}
</label>
{{#each this.values}}
<input
class="form-radio"
type="radio"
id="attribute_rectangle__{{../id}}_{{id}}"
name="attribute[{{../id}}]"
value="{{id}}"
{{#if selected}}
checked
data-default
{{/if}}
{{#if ../required}}required{{/if}}>
<label class="form-option" for="attribute_rectangle__{{../id}}_{{id}}" data-product-attribute-value="{{id}}">
<span class="form-option-variant">{{this.label}}<br>{{product.sku}}</span>
</label>
{{/each}}
</div>
I've tried inserting {{product.sku}} inside the label - as you can see above, but that doesn't work - nothing populates. I think it needs to reference the option with a "this" in there somewhere, but that's the extent of my coding savviness.
A single product attribute does not necessarily determine the variant, as there may be more attibutes, a combination of which would determine a specific variant (e.g. "Size" and "Color" Vs. just "Size").
That said, when (and only when) you have variants defined by a single product attribute (e.g. "Size"), you could actually bind a specific SKU to each of the attribute values (e.g. "30ml" => sku "AAA", "50ml" => sku "BBB").
I'm afraid the variant SKUs are not included in the data available as part of the "values", for the reasons above.
In fact, if you add the "debug" line (useful sometimes) using the "json" helper:
{{#each this.values}}
<input
class="form-radio"
type="radio"
id="attribute_rectangle__{{../id}}_{{id}}"
name="attribute[{{../id}}]"
value="{{id}}"
{{#if selected}}
checked
data-default
{{/if}}
{{#if ../required}}required{{/if}}>
<label class="form-option" for="attribute_rectangle__{{../id}}_{{id}}" data-product-attribute-value="{{id}}">
<span class="form-option-variant">{{this.label}}</span>
</label>
<!-- {{{json this}}} -->
{{/each}}
(note "json this"), you will see that the HTML produced only includes, for each variant, the "label", "id" (variant ID), "data", and "selected" properties, no variant SKU in there...
<!-- {"label":"30ml","id":104,"data":"30ml","selected":false} -->
If you can identify the product variant ID (the above is the option value ID, not a variant ID), you can retrieve the missing data using the BigCommerce Store Front API (specifically GraphQL) and JavaScript, and then use that data to inject SKUs in your HTML, see the following example from BigCommerce:
https://developer.bigcommerce.com/api-docs/storefront/graphql/graphql-storefront-api-samples#get-variant-details-as-a-product-object
That JavaScript would look something like this:
<script>
(function(w) {
const sfApiToken = '{{json settings.storefront_api.token}}';
if (sfApiToken) {
w.document.querySelectorAll('[data-vidsku]').forEach((e) => {
const vid = e.getAttribute('data-vidsku') || null;
if (vid) {
const queryS = `query VariantById {
site {
product(variantEntityId: ${vid}}) {
sku
}
}
}`;
fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${sfApiToken}`
},
body: JSON.stringify({query: queryS})
})
.then((res) => res.json())
.then((json) => {
e.textContent = json.product.sku || '';
});
}
});
}
})(window);
</script>
I'm having a few issues implementing the Mentions plugin in CKEditor4:
The outputTemplate isn't acting as expected. The <span class="tag is-delete"></span> from the template is completely omitted when inserted into the editor after selecting from the mentions dropdown.
The outputTemplate is inserted in a separate <p> tag all by itself, whereas I want the tags to be inline.
Example of current output:
<p>After looking into this issue, I can confirm</p>
<p><a data-value="1" class="tags has-addons"><span class="tag is-info">John Doe</span></a></p>
<p>'s bug report is reproducible in all major production releases; therefore, further escalation is required.</p>
Example of expected/desired output:
<p>After looking into this issue, I can confirm <a data-value="1" class="tags has-addons"><span class="tag is-info">John Doe</span><span class="tag is-delete"></span></a>'s bug report is reproducible in all major production releases; therefore, further escalation is required.</p>
My relevant code
My exact CKEditor configuration can be viewed here.
I'm using the Div Editing Area plugin in place of the iframe, so that my global css (Bulma) is utilized for the tags inside the wysiwyg editor.
<div class="field">
<p class="control" id="discussion-inputs">
<textarea id="discussion-textarea" class="textarea" placeholder="Add a comment..." style="margin-top: 0px; margin-bottom: 0px; height: 128px;"></textarea>
</p>
</div>
CKEDITOR.replace( document.querySelector( '#discussion-textarea' ), {
allowedContent: true,
mentions: [
{
marker: '#',
minChars: 3,
feed: "{{ url_for('api.user_list') }}",
itemTemplate: '<li data-id="{id}" class="dropdown-item">{name}</li>',
outputTemplate: '<a data-value="{id}" class="tags has-addons"><span class="tag is-info">{name}</span><span class="tag is-delete"></span></a>'
}
]
});
Small sample of the output received from the api.user_list endpoint
[
{
"email": "johnd#email.com",
"id": 1,
"name": "John Doe"
},
{
"email": "janed#email.com",
"id": 2,
"name": "Jane Doe"
}
]
My questions
How can I make the entire outputTemplate actually output without being truncated or stripped of any of the supplied html tags/classes?
How can I make sure the tags are inserted inline instead of as separate, new <p> tags, so there are no unneccessary linebreaks added to the typed message?
Bonus: How can I make it so the mention tag, after it's properly inserted into the editor area, when clicked will be removed instead of the cursor being placed at the spot of the text that was clicked? The idea is to prevent the user from being able to modify the #'d username to one that is not valid.
This issue only happens in my commercial project. It does not happen in my other projects and there is no difference that I can see in set up other then my current project is running the latest update of Kendo (but others in the office are running with the latest version with no issues). Same MVC version, all using server side validation.
So this is the problem
Working scenario 1
Fill in form data
Select something in drop down
Hit Submit
Works
Working scenario 2
Fill in form data
Select something in drop down
Leave a text field unfilled
Hit Submit
Validation error on text field
Enter text
Hit submit
Works
Failing Scenario:
Fill in form data
Don't select something in drop down
Hit Submit
Validation error on drop down
Select something in drop down
Hit submit
Repeats validation error and sets drop down back to unselected
This is currently using server side validation.
When I compare one of our working kendo drop downs to the one that isn't there are two things that stand out.
The working drop down, after validation fail, when I change its selection adds a span with "k-input" that has the selected value in text form. (The broken one does not)
The broken drop down has a value field whereas the working one doesn't
The Kendo Razor from the none working project is this:
#Html.Kendo().DropDownListFor(model => model.EmployeeRecordId).OptionLabel("Please Select").DataTextField("FullName").DataValueField("EmployeeRecordId").DataSource(source => { source.Read(read => { read.Action("Get", "EmployeeRecord", new {area = "ClientArea", id = ViewBag.ClientId}); }).ServerFiltering(true); }).Events(e => { e.Change("employeeChanged"); })
The one that does work is a lot less complicated, it doesn't need to be able to update (there's a button to add a new employee on that page)
#Html.Kendo().DropDownListFor(model => model.CurrencyId).BindTo(ViewBag.Currencies).OptionLabel("Select Currency")
Below is the HTML for each, taken from the page source just after the second validation error and a value was re-selected:
Working
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input class="input-validation-error" data-val="true" data-val-number="The field Currency must be a number." data-val-required="The Currency field is required." id="CurrencyId" name="CurrencyId" type="text" />
<script>
jQuery(function() {
jQuery("#CurrencyId").kendoDropDownList({
"dataSource": [{
"Text": "GBP",
"Value": "1"
},
{
"Text": "EUR",
"Value": "3"
}
],
"dataTextField": "Text",
"dataValueField": "Value",
"optionLabel": "Select Currency"
});
});
</script>
<span class="field-validation-error" data-valmsg-for="CurrencyId" data-valmsg-replace="true">The Currency field is required.</span>
Not Working
<span class="field-validation-valid" data-valmsg-for="EmployeeRecordId" data-valmsg-replace="true"></span>
</div>
<div class="editor-field">
<input data-val="true" data-val-number="The field Employee Name must be a number." data-val-required="The Employee Name field is required." id="EmployeeRecordId" name="EmployeeRecordId" type="text" value="3032" />
<script>
kendo.syncReady(function() {
jQuery("#EmployeeRecordId").kendoDropDownList({
"change": employeeChanged,
"dataSource": {
"transport": {
"read": {
"url": "/ClientArea/EmployeeRecord/GetAllActiveByClientId/1003",
"data": function() {
return kendo.ui.DropDownList.requestData(jQuery("#EmployeeRecordId"));
}
},
"prefix": ""
},
"serverFiltering": true,
"filter": [],
"schema": {
"errors": "Errors"
}
},
"dataTextField": "FullName",
"dataValueField": "EmployeeRecordId",
"optionLabel": "Please Select"
});
});
</script>
<span class="field-validation-valid" data-valmsg-for="EmployeeRecordId" data-valmsg-replace="true"></span>
</div>
Does anyone have any suggestion why this might be happening.
--Update--
Another key point of the puzzle, when it is sent to the server, "EmployeeRecordId" is not included in the form collection of keys!
--UPDATE 2--
when VS is paused on the "Create" action (where i am checking the form collection) if I go back to the page, I can see that the drop down box is mysteriously not there, like its been removed via JS pre submit
After much digging I came across a similar issue.
https://www.telerik.com/forums/kendo-validation-does-not-work-the-second-time
Which although didn't provide me an answer for why the server side is failing. It did lead me to how to get client side validation working for kendo drop downs. Which as it happens before sever side seems to stop the error ever happening.
To enable client side validation on kendo drop downs you need to add this code to the very bottom of your page (so the very bottom of your layout file)
<script type="text/javascript">
$.validator.setDefaults({
ignore: ""
});
</script>
You will need to enable the usual mvc client side validation with the jquery scripts.
I'm hesitant to mark this as best answer as it doesn't answer the question of why this is happening at all but I have posted it to help others with the same problem :)
Not the ideal solution.
But you'll have to add following code for every form submission with validations.
Found the solution from the Kendo UI official Support page. It looks more like a bug.
To get it working, you can add the following code at the bottom of you page. (After the page is loaded)
$(document).ready(function () {
$(".k-widget").removeClass("input-validation-error");
});
Hi there Im trying to do a few things with jQuery validation plugin and seems stuck on one place.
Here is some code:
<script type="text/javascript">
$(document).ready(function(){
$('#myform').validate();
$('#email').rules('add', {required: true, messages: {required: 'email is required'}} );
$('#phone').rules('add', {required: true, messages: {required: 'phone is required'}} );
$('#validate').click(function(){
$('#result').text($('#myform').validate().form());
return false;
});
});
</script>
<form id="myform">
<div>email:<input type="text" id="email" /></div>
<div>phone:<input type="text" id="phone" /></div>
<div id="result"></div>
<input id="valdate" type="image" src="images/submit.png" />
</form>
As a result i keep getting a wrong error message. If i click on submit button 'phone is required' is shown near email input and 'email is required' isnt shown at all.
Whats wrong with this code ?
You might consider something like the below. It's a bit clearer to read and debug. Since you are using standard rules like "required", you don't have to specify a message unless you want something different. The rules and messages are identified by the name of the input field (e.g. email).
The errorPlacement option is where you specify the location of the messages. You don't have to include this option; the default is to append the message to the input field. But if you have layout divs or need special position for message on radio boxes, or what have you, this is the place to do it.
$(document).ready(function(){
$('#myform').validate({
rules:{
email: "required",
phone: {required:true, minlength:7}
},
messages:{ //not required as default message for "required" rule makes same text
email: "email is required",
phone: "phone is required",
},
errorPlacement: function(error, element) { //this is where to put positioning rules
error.appendTo(element.parent()); //just an example
}
});
});
OK It seems like I've found the problem.
You HAVE to add NAME attribute to elements anyway.
In my example if you add appropriate names to input elements it will work nice.
The following approach:
<script type="text/javascript">
$(function(){
$('#myform').validate({
rules: {
phone: 'required',
email: 'required'
},
messages: {
phone: 'phone is required',
email: 'email is required'
}
});
});
</script>
along with adding name attribute to each input fields, works perfectly.
Try adding the rules first and then calling $('#myform').validate()
It will not work. You have to call validate method first.
Using input names approach
I know i can do it using names as you mentioned above.
But unfortunately i will have to use ids.
content will not be constant. It will vary depending on some rules. So as a result almost each time i will have a different page.
There are will be many controls with different ids. many validation groups etc.
So using "names approach" just doesnt meet my requirements.
Any thoughts how to use $(selector).rules('add') approach??
P.S.
I've found following example http://www.coldfusionjedi.com/index.cfm/2009/2/22/Using-jQuery-to-add-form-fields--with-validation and it works pretty nice and there is nothing special in code.
can we use google AJAX Language API with EXTjs?????
i have tried example for translitration i have one html file
and typemarathi.js
google.load("elements", "1", { packages: "transliteration" });
function onLoad() {
var options = {
sourceLanguage: google.elements.transliteration.LanguageCode.ENGLISH,
destinationLanguage: [google.elements.transliteration.LanguageCode.MARATHI],
shortcutKey: 'ctrl+g',
transliterationEnabled: true
};
// Create an instance on TransliterationControl with the required
// options.
var control = new google.elements.transliteration.TransliterationControl(options);
// Enable transliteration in the editable DIV with id
// 'transliterateDiv'.
control.makeTransliteratable([myname]);
}
google.setOnLoadCallback(onLoad);
it works fine.
but if i write the textfield in extjs
Ext.onReady(function(){
var form1=new Ext.FormPanel({
renderTo:document.body,
frame:true,
title:'My First Form',
widyh:250,
items:[{ xtype:'textfield', fieldLabel:'First name', name:'firstname'}]
});
});
and try to pass firstname (name attribute to control.makeTransliteratable([firstname])) then it does not work... it says invalid id error
but if i pass->(html textfiled name to it) control.makeTransliteratable([myname]) it works fine
(i want to type and display multiple nonEnglish languages data
programatically frontend i used EXTjs is there any another way to do so if yes the suggest me. pls..
Yes you can.
Besides someone should clean his code, thats hurrible.
Yes, you can. But you should know that ExtJs automatically generates identifiers for html elements:
html:
<div class="x-form-item x-form-label-left x-box-item" id="ext-gen27" style="left: 0px; top: 0px;">
<label style="width: 55px;" class="x-form-item-label" id="ext-gen28">Send To:</label>
<div style="padding-left: 60px; width: 668px;" class="x-form-element" id="ext-gen26">
<div class="x-form-field-wrap x-form-field-trigger-wrap x-trigger-wrap-focus" id="ext-gen24" style="width: 668px;">
<input type="text" name="to" id="ext-comp-1002" autocomplete="off" size="24" class=" x-form-text x-form-field x-form-focus" style="width: 651px;">
</div>
</div>
</div>
js:
....
items: [{
xtype: 'combo',
store: ['test#example.com', 'someone-else#example.com' ],
plugins: [ Ext.ux.FieldReplicator, Ext.ux.FieldLabeler ],
fieldLabel: 'Send To',
name: 'to'
}]
As I understand you need to translate the label. In order to do this you should get the id of the label. To do this you can use TextField's label property (myField.label.id). If you want to translate a lot of elements then probably it'll be better for you to use something like this:
var control = new google.elements.transliteration.TransliterationControl(options);
var labelIds = [];
Ext.each(Ext.select('label'), function(item){
labelIds.push(item.id);
});
control.makeTransliteratable(labelIds);
But be aware that you should call this only after rendering all elements. Also you can write a some plugin that will inject this functionality into 'render' method. Writing a plugin is a better but a bit more harder way.