Use mustache for templating smaller parts for use multiple times in a form - forms

Okay. So I hope this is specific enough.
I'm, kind of new to mustache, but see it has great potential, so why not use it.
I'm making a quite big form, and want to have the form built with mustache. So i have started to make the form in mustache and, then i realized i want to template the form-elements. One template for how i want every narrow input, wide input, select etc. to look like. because now i'm repeating myself.
My template and partials are provided through $.ajax get, where the main form template are defined as a mustache file, with html content, and the partials are defined as a mustache file with every template inside -tags.
Variables for mustache to use. This object is somewhat subject for change.
var jsonForm = {
oneInputField: {
value:'put your title here',
rule_set: {
required: {
strName: 'required',
strErrorMsg: 'error message'
}
}
},
oneSelect: {
options: [
{value: '- Pick one -', helper: 'helper', select_options: {disable_search: true}},
{value: 'option1', selected: true},
{value: 'option2'},
{value: 'option3'},
{value: 'option4'}
],
rule_set: {
required: {
strName: 'required',
strErrorMsg: 'error message'
}
}
}
};
How i fetch the data
$.ajax({
url: 'myForm.mustache',
type: 'get',
success: function(template) {
$.ajax({
url: 'myFormElements.mustache',
type: 'get',
success: function(partials) {
var $html = Mustache.render(template, jsonForm.fields, partials);
$('div#formContent').html($html);
$('div#formContent select').chosen();
if (jsonForm.fields.title.length > 1) {
$('div#header').html(jsonForm.fields.title);
}
}
});
}
});
Partials. Would actually like to have it all in separate files, but it doesn't seem to be possible without making a ton of ajax calls, so I keep with my current two mustache templates.
<script type="text/html" id="inputNarrow">
<label>{{label}}:</label><input value="{{value}}">
{{#rule_set.required}}<div class="required">*</div>{{/rule_set.required}}
{{^rule_set.required}}<div class="not-required"> </div>{{/rule_set.required}}
<div class="clearfix"></div>
</script>
and my form-template
<div id="formContainer" class="border-box">
<div class="group-box">
<p>Fields marked with <span class="required">*</span> are required to complete the form</p>
</div>
<div class="group-box">
<h2>Partial element test</h2>
<div class="form-container">
{{>partials.inputNarrow}} <-- I have to be able to specify what data I want to enter here.
</div>
<div class="form-container">
{{>partials.selectNarrow}} <-- I have to be able to specify what data I want to enter here.
</div>
</div>
So my question is is it possible for a bigger one big unique mustache-template to use "element"-templates (also in mustache), for rendering?
I am not very open to adding additional libraries to my project, like ICanHaz or similar, since this is for work.
Really sorry if this question is answered before, but I couldn't find it

I found an alternative way of doing what I tried to do.
I'm not sure if it's any good, but it does the job.
I used the possibility of making functions inside the object sent to the main-tempalte "form-template".
wich looks like this:
var smallRender = function(url, containerId, objData) {
$.ajax({
url: url,
type: 'get',
success: function(template) {
var $html = Mustache.render(template, objData);
var $objContainer = $('div#' + containerId);
$objContainer.append($html);
}
});
};
the actual object
oneInputField: {
value:'put your title here',
rule_set: {
required: {
strName: 'required',
strErrorMsg: 'error message'
}
},
getRendered: function() { // I would like to cache this somehow
smallRender(templateUrl.input.narrow, jsonForm.fields.title.containerId, {
label: jsonForm.labels.title,
field: jsonForm.fields.title,
required: isRequired(jsonForm.fields.title)
});
}
},
So basicly i send an ajax call to get the main template, and for each element in the form I want to present, i call on the getRendered in main-tamplate mustache, and it basicly renders the content with the smaller template.
tempalte url is basicly a collections with the urls to all the templates. so if I specify templateUrl.input.narrow i will get the narrow input element and so on.
Not sure as I mentioned if this is the "correct" way of doing it, or how good it will scale in a big environment, but it works.
I will mark my this as the correct answer (if I'm even allowed), since there are no other answers that solves my problem.

Related

ISML to lit-html

I'm having difficulties with rewriting ISML-Templates to lit-html.
e.g.
<isset name="Variable" value="${pdict.variable}" scope="page" />
How does the isml tag <isset> work for lit-html?
Lit-html speaks regular HTML. You can define any custom element you want, but <isset> is neither a standard nor a custom element. Meaning, <isset> element doesn't work with lit-html per-se, rather, lit-html takes your template and updates the DOM efficiently with it. If you have some other code on the page which is parsing the rendered <isset> elements, that's fine, you can use lit-html to render them.
lit-html will render nodes as you write them, although it will transform that self-closing tag to a normal tag.
(async function() {
const { render, html } = await import("https://unpkg.com/lit?module");
function issets(items) {
return items.map(({ name, value }) => html`<isset name="${name}" value="${value}"/>`);
}
render(issets([
{ name: 'a', value: 1 },
{ name: 'b', value: 2 }
]), document.querySelector('output'));
console.log(document.querySelector('output').innerHTML)
})();
<output></output>
Rendered output:
<!----><!----><isset name="a" value="1"></isset><!----><!----><isset name="b" value="2"></isset><!---->

React with server side variables

I'm rendering out components that have properties with liquid strings. These components are being rendered on the server and picked back up again in the client. Essentially I'm using the DOM as a data store. I'm debating on methods of where to store the data. I need the component to render out valid markup to the server for SEO. But I don't need to pick back up the variable like I am here with this.refs.variantId.getDOMNode(). I could for instance set the variantId to a global client side javascript variable somewhere higher then this code in essence something like var variantId = "{{ product.variants[0].id }}";.
This component will render to a string and be placed within a template file on a server, the server will process that HTML come across the {{ product.variants[0].id }} variable and turn it into something like 1058477584. My component needs to reach into the existing DOM for itself and pull the value out.
var React = require("react");
var $ = require("jquery");
module.exports = React.createClass({
handleSubmit: function(e){
e.preventDefault();
var variantId = this.refs.variantId.getDOMNode().value.trim();
$.ajax({
url: "/cart/add.js",
method: "post",
dataType: "json",
data: {
"id": variantId,
"quantity": this.props.quantity,
},
success: function(data) {
// emit cart added event
}.bind(this),
error: function(xhr, status, err) {
// emit error event (cart added)
}.bind(this)
});
},
getDefaultProps: function(){
return {
quantity: 1,
variantId: "{{ product.variants[0].id }}",
buttonText: "Add to cart"
}
},
render: function() {
return (
<div className="buyButton">
<form action="/cart/add" method="post" encType="multipart/form-data" onSubmit={this.handleSubmit}>
<input type="hidden" name="quantity" value={ this.props.quantity } />
<input type="hidden" name="id" ref="variantId" value={ this.props.variantId } />
<button type="submit" className="btn btn-holstee">{this.props.buttonText}</button>
</form>
</div>
);
}
});
I'm wondering what people think about rendering components with another templating language as a string property. Does it make sense to store that data anywhere else? I don't have access to a server that can store individual pages. It's all templates so multiple data sources need to be handled by one route.
Is there a better way to abstract the liquid out of the component?
Is there a better way to call DOMNodes / update all the props to DOMNodes?
I do something similar in my app. I serialize with JSON and put it in a script tag in the DOM
<script type="application/json" id="preload-notifications">{{json_encode($preload_notifications)}}</script>
Then,
var raw = document.getElementById('preload-messaging');
if (raw === null) {
return ;
}
var data = JSON.parse(raw.text);
I use the flux architecture so it's really simple
this.dispatch('messaging', {
messages: data
});
But you could can inject it as a prop.
React.render(<MessagingContainer messages={data} />, messageDomNode);
Whatever you do, I suggest you don't query the DOM inside a React component. Try to pass stuff as props as much as possible.

How do I get element related to active input in jQuery UI Autocomplete?

I'm trying to pass a custom form attribute (category) through jQuery UI Autocomplete to use in a product search. The form looks like <form id="BulkOrderForm" category="samplecategory"><input></input>...</form> and contains inputs that use the autocomplete script. There can be several forms on each page, so I need to be able to get the category value from the form that contains the active input field.
Here's my source:
function autocomplete() {
$("input.wcbulkorderproduct").autocomplete({
element: function(){
var element = $('form#BulkOrderForm').attr('category');
return element;
},
source: function(request, response, element){
$.ajax({
url: WCBulkOrder.url+'?callback=?&action='+acs_action+'&_wpnonce='+WCBulkOrder.search_products_nonce,
dataType: "json",
data: {
term: request.term,
category: element
},
success: function(data) {
response(data);
}
});
}
});
}
Any thoughts on how this can be acheived?
If I'm understanding correctly, you're trying to use the active input's parent form in the ajax request. Here's a way to achieve that:
Html:
<form data-category="form1">
<input type="text" />
<input type="text" />
</form>
<form data-category="formB">
<input type="text" />
<input type="text" />
</form>
JS:
$('form').each(function () {
var category = $(this).data('category');
$(this).find('input').autocomplete({
source: function (request, response) {
response([category]);
}
});
});
Instead of using autocomplete on a catch-all selector that gets inputs from all forms, first select the forms themselves. For each one, extract the category, then select all child inputs and call autocomplete on that result. Then you can use the category variable in the ajax call - in the example I'm simply passing it to the callback to display.
http://jsfiddle.net/Fw2QA/
I'll give you another solution, you can lookup the parent form of the active input, and extract the attribute from it. Because I don't know if this category in your form is dynamic or no, or either if you can control all of the process involved in your code, I'll give you a more generic solution, although if that attribute is dynamic "Turch" solution is way better than mine, by letting the data functionality of jquery handle the attribute changes, if it's static, than you can just do it like this:
function autocomplete() {
var element = $("input.wcbulkorderproduct").autocomplete({
source: function(request, response){
$.ajax({
url: WCBulkOrder.url+'?callback=?&action='+acs_action+'&_wpnonce='+WCBulkOrder.search_products_nonce,
dataType: "json",
data: {
term: request.term,
category: element
},
success: function(data) {
response(data);
}
});
}
}).parents('form').first().attr('category');
//chained call, sets autocomplete, grabs the parent form and the attribute
//which is saved on the variable element, and is used on every call through
//javascript context inheritance.
}
UPDATE
A little example illustrating my suggestion (provided by #Turch > thanks), can be found here.

Select2-rails passing data to form field

I'm trying to implement select 2 using the select2-rails gem but I'm not familiar with jQuery or rails.
I basically tried to copy the placeholder example from this website and adapt it to my needs:
http://rails-select2-example.herokuapp.com/
I have a field which lists performers for an event. Originally I just had a simple text field for :performer. But I'd like replace this with a lookup based on my users profile_name which I can then assign to the :performer field.
So I have something like this:
<%= select_tag "performer", options_from_collection_for_select(#user, "id", "profile_name"), include_blank: true, id: "performer", data: { placeholder: "Choose a performer" } %>
Followed by this:
<script type="text/javascript"> $(document).ready(function() {
$('select#performer').select2({
placeholder: "Choose a performer",
allowClear: true
});
});
</script>
Which works and gives me a dropdown of the users. But I'm not sure how to pass this information to the :performer field. This is probably really simple, so much so that whenever I've searched for simple2 nowhere seems to mention how you pass it to the field. Please help!
Update1:
I can get it to submit by using the following BUT it becomes a simple select box rather than being a select2 autocomplete box.
<%= f.select_tag "performer", options_from_collection_for_select(#user,
"profile_name", "profile_name"), include_blank: true, id: "performer", data:
{ placeholder: "Choose a performer" } %>
Update2:
Got it to work but still cannot get the placeholder to display.
<%= f.select :performer, options_from_collection_for_select(#user,
:profile_name,:profile_name), {}, include_blank: true,
id: "performer", data: { placeholder: "Choose a performer" } %>
Instead of writing data:{placeholder:"Choose a performer"} prefer writing directly after the comma placeholder: "placeholder value" in my opinion it should work .

AngularJs Directive: Using TemplateURL. Replace element. Add form input. Getting form.input.$error object

Not sure if this is possible but I'm trying, and keep coming up short.
http://plnkr.co/edit/Gcvm0X?p=info
I want a 'E' (element) directive that is replaced with a more complex nested HTML node using the 'templateUrl' feature of directives.
HTML defining the directive (form tag included for complete mental image):
<form id="frm" name="frm">
<ds-frm-input-container
class="col-md-1"
frm-Name="frm"
frm-obj="frm"
input-name="txtFName"
ds-model="user.firstName"></ds-frm-input-container>
</form>
TemplateUrl contents which 'replaces' the above directive 'ds-frm-input-container' HTML element:
<div>
<input
required
ng-minlength=0
ng-maxlength=50
class="form-control"
ng-model="dsModel"
placeholder="{{dsPlaceHolder}}" />
<span ng-if="showErrs" class="label label-danger">FFFFF: {{dsModel}}</span>
</div>
Controller and Directive:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = "Nacho";
$scope.user = {};
$scope.user.firstName = "";
})
.directive('dsFrmInputContainer', function(){
var ddo = {
priority: 0,
restrict: 'AE',
scope:
{
frmName: '#',
inputName: '#',
dsPlaceHolder: '#',
dsModel: '=',
frmObj: '='
},
templateUrl: 'template1.html',
replace: true,
controller: function($scope)
{
$scope.showErrs = true;
},
compile: function compile(ele, attr) {
return {
pre: function preLink(scope, ele, attr, controller)
{
},
post: function postLink(scope, ele, attr, controller)
{
var txt = ele.find('input');
txt.attr('id', scope.inputName);
txt.attr('name', scope.inputName);
//BLUR
txt.bind('blur', function () {
console.log("BLUR BLUR BLUR");
angular.forEach(scope.frmObj.$error, function(value, key){
var type = scope.frmObj.$error[key];
for(var x=0; x < type.length; x++){
console.log(type[x]);
}
});
event.stopPropagation();
event.preventDefault();
});
}
};
},
};
return ddo;
});
The directive replaces just fine and the input element is named just fine. The form object however doesn't include the input element name in the error information. This makes it impossible for me to single out the input element during a 'blur' event that is setup in the directive.
I am doing this trying to reduce the show/hide logic 'noise' in the html for error messages (spans) and it should be reusable.
UPDATE (2014.01.28):
2014.01.28:
Added promises. There is a service that allows validation on button clicks. NOT USING built in angular validation anymore found some compatibility issues with another library (or viceversa).
ORIGINAL:
Here is my form validation directive vision completed (plnkr link below). Completed in concert with the help of the stack overflow community. It may not be perfect but neither are butterfingers but they taste good.
http://plnkr.co/edit/bek8WR?p=info
So here is a link that has the name variables set as expected on the given input form error object. http://plnkr.co/edit/MruulPncY8Nja1BUfohp?p=preview
The only difference is that the inputName is read from the attrs object and is not part of the scope. This is then read before the link function is returned, in the compile phase, to set the template DOM correctly.
I have just spent quite a while trying to sort this problem out, and while this is not exactly what you were looking for, his is my attempt. It uses bootstrap for all the styling, and allows for required and blur validation, but its definitely not finished yet. Any thoughts or advice much appreciated.
https://github.com/mylescc/angular-super-input