ermouth / jquery.my Goto Github PK
View Code? Open in Web Editor NEWjQuery.my is a plugin that binds form controls with js data structures.
Home Page: http://jquerymy.com
jQuery.my is a plugin that binds form controls with js data structures.
Home Page: http://jquerymy.com
Hello,
Sorry for not labeling this as question, but I can not add labels.
I am having a very bad experience trying to update a text field from a modal popup. The layout is a bit complex, and I am getting a bit lost tracking how children sees the data object. I'll try to specify the layout:
Form
So there are three levels of nested manifest: the main one, the manifest for each column and then another manifest for the modal popup. The modal popup has a button, which bind function perform some stupid calculations, and then stores the result in the data object. The problem is that when the modal closes, the data updated is not reflected on the column (parent). I based the modal in your example of the main website(copy and paste, same _updateMe function), but in it there is no update from any function, just good old object --> fields binding. I don't know if it matters, but I am passing just the whole data object to the modal child manifest.
Also it will be nice if you have time to explain me how the data object is passed to children. It looks like magic for me when I only have to use "text" (for example) as identifier inside a repeated section, and it is magically bind to the correct item inside the list.
Thank you very much.
Sorry if this is the wrong place to report, but if you input "< h1 >" (html without spaces) into the Luke Skywalker input field at http://jquerymy.com/, the layout breaks.
Tried with:
select2 4.0.3 (regular + full)
select2 3.5.1 (regular + full)
manifest as follows:
var manifest = {
data : {id: 18},
init: function($form) {
$form.html(this.HTML);
return factory.getRates()
.then( response =>{
this.RATES = response;
console.table(this.RATES);
} );
},
ui: {
"#uk": {
init: function ($component) {
$component.html(this.RATES
.reduce((prev, next) => prev + '<option value="' + next.id + '">' + next.uk + '</option>', ''));
$component.select2({
placeholder: "UK"
});
},
bind: function(data, value) {
console.log("UK -> Data: "+data.toString()+ " this.data: "+ this.data.toString() +" Value: "+value); //Debugging
var dm = data.id;
if(value !== null) dm = value;
return dm;
},
recalc: "#eu, #usa",
recalcDepth: 1
},
"#eu": {
init: function ($component) {
$component.html(this.RATES
.reduce((prev, next) => prev + '<option value="' + next.id + '">' + next.eu + '</option>', ''));
$component.select2({
placeholder: "EU"
});
},
bind: function(data, value) {
console.log("EU -> Data: "+data.toString()+ " this.data: "+ this.data.toString() +" Value: "+value); //Debugging
var dm = data.id;
if(value !== null) dm = value;
return dm;
},
recalc: "#usa, #uk",
recalcDepth: 1
},
"#usa": {
init: function ($component) {
$component.html(this.RATES
.reduce((prev, next) => prev + '<option value="' + next.id + '">' + next.usa + '</option>', ''));
$component.select2({
placeholder: "USA"
});
},
bind: function(data, value) {
console.log("USA -> Data: "+data.toString()+ " this.data: "+ this.data.toString() +" Value: "+value); //Debugging
var dm = data.id;
if(value !== null) dm = value;
return dm;
},
recalc: "#uk, #eu",
recalcDepth: 1
}
},
HTML:[
`<div class="row">
<div>
<select id="uk"></select>
</div>
<div>
<select id="eu"></select>
</div>
<div>
<select id="usa"></select>
</div>
</div>`
],
RATES: []
};
I can see that the values of each dropdown is updated correctly since when I click on it the correct value is already pre-selected, however the currently displayed value on the other two dropdowns does not change.
If I try to fire a change event myself, the values change however the app halts in an infinite loop of recalc cycles.
This is more of a suggestion than an issue but i would suggest adding some minor A11Y attributes on the
.my("errors")
function.
heres how i did it.
line 923 - inside if (r = a.hasClass("my-form-list")
i added the removeAttr here:
f.removeClass(y), f.children("input").removeAttr("aria-invalid"),
then on line 929 - inside the final else
i added the attr here:
f.addClass(y), u.errors[m] = v;
f.children("input").attr("aria-invalid", "true");
of course the user still needs to handle labels properly but im already doing that on my save
function but this is pretty standard form validation.
Thanks!
Regexps in this fn https://github.com/ermouth/jQuery.my/blob/master/Release/1.2/jquerymy-1.2.4.js#L727 may produce enormously deep recursion and exhaust js machine stack.
Minor bug, this function is never used during normal runtime.
Screens for local modals are shifted or have invalid size (do not entirely cover content) for elements with padding.
Global modals irreversibly disable scroll after close in Edge.
Hi,
This is a simplified version of what I'm trying to accomplish, in order to discuss it more easily.
I linked two fields using jQuery.my. Then I listen to changes on the first field and run an action when the change event fires.
The change event doesn't fire when the first field is updated by writing in the second field.
I feel like there would be a way to do this using jQuery.my, but after reading the documentation it's not very clear to me how to proceed.
Here is an example on CodePen: https://codepen.io/andreyu/pen/GBrpbj
<h2>Form</h2>
<form action="" id="form">
<div><input id="name" type="text" placeholder="Name" value="Anna" /></div>
</form>
<h2>Form 2:</h2>
<form action="" id="form2">
<div><input id="name2" type="text" placeholder="Name" /></div>
</form>
<br><br>
<script type="text/javascript">
// Init $.my over DOM node
$("body").my({
// Init function
init: function ($node, runtime) {
},
// Bindings
ui: {
"#name": {bind: "name", watch: "#name2"},
"#name2": {bind: "name", watch: "#name"}
}
});
$("#name").on("change",function() {
alert("name changed");
});
</script>
In this example I would like an alert() to fire when writing in the second field.
Thank you for your time.
So I'm trying to update my whole data set when I click on a button, but it only does this once:
var one = {
title: "one",
price: "1"
};
var two = {
title: "two",
price: "2"
};
// Manifest
var manifest = {
//Default data
data: {
title: "",
price: ""
},
// Bindings
ui: {
"#db_title": {bind: "title"},
"#db_price": {bind: "price"}
}
};
// onClick
$("#page").my("data", one); // this works
// on second click (other button)
$("#page").my("data", two); // this doesn't work anymore!?
Switching them causes same behavior. While setting one element (title for example) does work all the time.
I've been trying to solve this, but I'm all out of ideas.
I'm trying to dynamically assign selectors for the form since these are rendered by the server.
"ui":{
"#Text1": { bind: "Text1" },
"#Setting6": { bind: "Setting6" },
"#Setting7": { bind: "Setting7" }
}
So this is the target selectors, but i cannot use code here afaik to get the attribute data from the selector dynamically.
The selector where get the data from looks like this:
<div class="editable header" data-fieldname="Text1" data-fieldtype="header" data-setting2="Setting7" data-setting1="Setting6"></div>
The only "solution" i've come up with is to extend manifest after the JSON have been loaded form store, but that ruins the portability of the manifest.
manifest.ui = { }
manifest.ui["#"+$('.editable.header').data('fieldname')] = {bind: $('.editable.header').data('fieldname')}
manifest.ui["#"+$('.editable.header').data("setting1")] = {bind: $('.editable.header').data("setting1")}
manifest.ui["#"+$('.editable.header').data("setting2")] = {bind: $('.editable.header').data("setting2")}
Any other ways to retrieve it dynamically directly in the manifest?
Animation definitions like
{
style:{
'@keyframes somename': 'from {} to{}'
}
}
are prefixed as other class names during init. Result breaks animations, cause looks like this:
<style>
@keyframes somename {
.my-manifest-manid from {}
.my-manifest-manid to {}
}
</style>
Seems a combination of jquery 3 and newly introduced $.my optimizations.
引入jquery1.12.4,再引入jquerymy-1.2.0报 isS is not a function
$('#modal').modal('show') not working on pages with jquerymy (bootstrap 2). Any ideas?
Check functions for SELECT controls sometimes fail to apply result of validation over the control in case of a) invalid value, b) absence of container for error message.
This library looks really great! I think the big selling point is how we can get data binding but not have to signup for some bigger framework. However SugarJS is very intrusive and modifies natives. Unfortunately that means using this library ends up touching all parts of core javascript. Which is not something that I can sign up for in existing apps. If you could somehow disconnect yourself from this library (maybe use underscore?) I think that would really be helpful.
I understand this is technically not an issue. But I just wanted to bring it up. Thanks.
If a child form was statically initialized as a standalone control (not element of a list), it may report errors for a parent despite all controls are valid.
Happens at least if subform instantiated with invalid values.
So after correcting all invalid fields calling $('#childFormId').errors()
returns {}, but calling $('#parentFormId').errors()
may still report {'#childFormId':{'#ctrlN':'Error message'}
.
It shows TypeError: isS is not a function.
Hi,
Suppose you have two selects, one for country and other for state, example: select-1: USA and select-2: states of the USA.
When select-1 change it's value, we must update the select-2 with a new list of items (states) and clear the old selected value.
But the in the bind
event, I don't have any context about what I should do:
"#select-states": {
bind: function (d, v, $c) {
// This was called when the control changed it's own value?
// Or this was called when "select-country" changed it's value?
// Or this was called when the "redraw" method was fired (form initialize)?
// if the "select-country" control invoked this event, we should update the states.
// if the state value just changed, we shouldn't update the select2 list.
if (country changed) // how to do this?
$c.select2({ data: states });
// if the "select-country" value invoked this event, we should set this to null,
if (country changed) {
d.State = null; // The user must select a new value.
} else
d.State = v;
},
"watch": "#select-country"
}
Basically, I need I way to tell which event invoked the bind
method, so I can respond accordingly.
Looking for when the value
parameter is null doesn't work, it doesn't make clear which event invoked the bind function
(sometimes null could be a legit value).
Thanks.
Btw, @ermouth, I tested your suggestion of implementation of select2 component (from PR comment), it's working good.
The data autofilled by browser like chrome auto-fill is not being read by the plugin unless the input fields are focused or touched.
The multiple select doesnt work with semantcui { http://semantic-ui.com/ }, i think that it also doest work with bootstrap , when i use the $ctrl.select2({}); in init it works but it buggs the layout just working with the select2 api , please help.
Could you please add support for both input[type="tel"]
and input[type="email"]
?
Modification would occur at line 319 as follows:
"[type='text'],[type='number'],[type='search'],[type='hidden'],[type='password'],[type='button'],[type='range'],[type='tel'],[type='email'],:not([type])":{
Line 319 in 5bce4a0
List ui entry may have own hash function, which may return values like names of default {} methods. In this case list entry init fails, breaking render of entire list.
Discovered dissecting ermouth/couch-photon#8 issue.
I'm having the same issue as others while trying to load jQuery.my.js
Below is the loading order. I have tried a lot a ways to load but keep getting the same error.
'web/webroot/_ui/responsive/global/js/responsive-global-header.js': [
ui_src_responsive + '/global/js/sugar/sugar.min.js',
ui_src_responsive + '/global/js/jquery-3.1.1.min.js',
ui_src_path + 'sourceFiles/js/blazy.min.js',
ui_src_responsive + '/global/js/jquery-ui-1.12.1.min.js',
ui_src_responsive + '/global/js/jquery.cookie-1.4.1.js',
ui_src_responsive + '/global/js/coffee-script-1.6.3.js',
ui_src_responsive + '/global/js/jquerymy/jquerymy.js',
Thanks!
Is there any way to destroy an instance?
I'm using .my in an admin panel and it works amazingly, but performance starts to be an issue after a few instanced forms. I'd rather load it on request and remove it when the editing modal is closed.
Form init just stays pending forever.
Seems like a bug in internal _snapshooter
function.
VueJS has a system called computed properties which can be used along side the data attributes setup. that can be manipulated before output.
Is this available within $.my? I'm doing some calculations where a number increments programmatically but the value doesn't update in the front end if it's done this way. I've tested this out with just changing a string programmatically and it suffers the same issue.
Different forms, starting simultaneously and having require sections with same URL, initiate multiple requests instead of sharing result of single request.
Can cause dramatical traffic increase and inintended server side loads.
Please support datetime and datetime-local type for input
Still grasping some fundamentels about webpack, but from what I gather plugin is not being applied on the global jquery? I've tried expose-loader and imports-loader approaches, and also have jquery on my ProvidePlugin object,
plugins: [
new webpack.ProvidePlugin({
jquery: 'jquery',
$: 'jquery',
jQuery: 'jquery',
"window.jQuery": 'jquery',
"Tether": 'tether',
"window.Tether": 'tether'
})
],
to no avail.
Can there be some instructions or suggested method of using this plugin with webpack in the docs?
When using jquery 1.9.0 I got this error "Cannot read property 'msie' of undefined".
First, awesome plugin, i love it.
I'm doing a dynamic form bind just like your Rockstar death demo.
so i see under ui > "element" > manifest > ui
there is
events: "click.my"
but it doesnt help much for keyboard accessibility. is there something we can add their for keydown events ?
i even have a jquery .keypress function listening to the list:
elements so if there is some external command to bind the form that way please let me know.
Thanks!
As you can see in my example, if I use a regexp to do the check, it shows the correct error message.
However, if I use a custom function, it simply returns an general "Error".
Hope you understand what I'm asking. Thanks.
Would it be possible to separate plugin helpers and jQuery UI stuff?
It bloats the jQuery.my core more than is needed for us that use our own frameworks (Semantic-UI in this case).
I am using jQuery.my to bind to a fairly complex object and really like its functionality. Unfortunately, though, I am having a problem where I am unable to create multi-line input in textareas in nested forms. It works ok in the main form but in my nested, repeated, forms the newlines just get "eaten up" - my cursor goes to the next line then immediately jumps back to the end of the first line. I am hoping that this is something that can be fixed. Thanks!
Setting/removing disabled state from <button>
using css:{":disabled":function(){/*...*/}}
sometimes doesn‘t work if button recalc is triggered externally using this.my.check('#btnId')
or similar ways.
Bug takes place intermittently and can not be reproduced if rule is not ":disabled", but smth like "cssRuleName"
or "self:cssRuleName"
.
Thanks @carpogoryanin for pointing out.
Hi!
Tell me, please, how about recursive rendering of forms? For example, resources tree or (theoretically) family tree - where every item has identical properties set in any deep level.
{
fullname: 'Some name',
age: 25,
city: 'NY',
childs: [{ /* array with child objects with identical properties set: 'fullname', 'age', 'city', etc.. */ }]
}
Currently, i don't understand how this can be done because every form should have unique id and form controls should bind with properties by unique "id" attribute too. Even if the bind properties by 'class'-selector like:
$(".form").my({ui:{
".fullname": "fullname",
".age": "age"
}}, data);
this could lead to conflict with delegated and bubbling events.
Whether there is possibility to recursive handling of this issue?
p.s. sorry for my bad english. I hope you understand me :)
Hello,
First of all thank you for this awesome library. It helps a lot to people like me, with any sense of organizing and setting it's own coding-rules (dash or underscore? or maybe camel case? arrays or objects as return? and a long list...)
I'm facing a small problem that I don't know if it is intentional, and if it is I wanna know how to avoid it. It is about repeated sections, I mean, child forms, nested forms or however you prefer to call it. I have a button which is binded to a function that triggers the "insert" method of the container binded to the array that holds the repeated section. Each time I click on the button I have to interact with the newly added control (is a text area) to be able to add another element to the list. If I click the button twice, nothing happens. Why? I though it was intentional on some examples (specifically coded for that) but seems to be the default behavior for everything. Could you help me? this makes my application very uncomfortable to use.
Thanks in advance
jquery v1.12.4 my.js 1.2.0
Hi, @ermouth , I've found a bug in the library.
Basically, if you put a check function in a nested list, the errors are not cleared when the form is valid again. If you call $form.my("valid")
, it returns false.
I reproduced it in the "repeated child form" example of http://jquerymy.com/api.html with a little modification to add a check function and a button to perform the checking.
STEPS:
1 - Click on the "Check Validity" button: since all passwords are filled, it alerts "true
".
2 - Empty one of the password boxes.
3 - Click on the "Check Validity" button: it alerts "false
",
4 - Fill the password box again.
5 - Click on the "Check Validity" button: it alerts "false
", even tough the password is filled again.
HTML:
<div>
<input id="name" type="text"
placeholder="Form ID" class="fs150 w400">
</div>
<div id="list">
<div class="row br2">
<span class="fi-list"></span>
<input id="id" type="text" placeholder="User login" class="w180">
<input id="pwd" type="password" placeholder="Password" class="w170">
<span class="fi-x red o50 pl5"></span>
</div>
</div>
<input id="btn-add" type="button" value="Add user" class="mt10">
<input id="btn-check" type="button" value="Check Validity" class="mt10">
JS:
// Repeated child form example
({
data: { name:"", users:[] },
ui: {
"#name":"name",
"#list":{
bind:"users",
manifest:"UserForm",
check: function(d,v){ if(v.findIndex(t => t.pwd === "") !== -1) return "Empty pass."; }, // <-- HERE
list:'>div.row',
init: function ($control) {
$control.sortable({ handle: ".fi-list" });
}
},
"#btn-add": function (data, val) {
if (null != val) this.my.insert("#list", {});
},
"#btn-check": function (data, val) {
if (null != val) {
alert($("#list").my("valid")); // <-- HERE
}
}
},
style:{
" #list>div":"width:400px; border-bottom:1px dotted #aaa;"
+"padding:5px 0 10px 0;margin:5px 0;"
},
UserForm:{
ui:{
"#id":"id",
"#pwd":"pwd",
".fi-x":{
bind: function (data, val) {
if (null != val) this.my.remove();
},
events:"click.my"
}
}
},
id:"Subform list"
})
You guys are doing a great job. I am very happy with this project.
It has given me a hope to support my jquery projects.
Hello,
seems that it doesn't work when I bind a child list form B with another child list form A.
Form A works well, but the form B cannot excute 'insert' or 'remove'.
And I also found that there is not a 'my-form-xxxx' class property in form B.
Tks for reading, expecting your reply.
Hi,
how do I detect the last row in a child form? I have a list and use the id
function to index items:
id: function(e, i) {
e.idx = i+1;
return 'c3-q-' + e.idx;
},
Detecting the first child with index 1 is easy. But detecting the last child is impossible right now. How to solve this issue?
Seems that issue takes place when list is bound to this.SomeArray
data source.
Setting $.my.locale does not affect forms starting after locale change. They start with locale of the browser tab.
This worked fine when the manifest was inline, but when loaded from JSON - any previously defined variables are unreachable.
I'm sorry for asking you this question here but I didn't found a better place.
I've been perfectly able to use jquerymy with a pretty complex data like this one
"parent": {
"property_one": "value_1",
"list": [
{
"name": "1",
"desc": "one",
"sublist": [
{
"name": "wow",
"value": "80"
},
{
"name": "more wow",
"value": "60"
}
]
},
{
"name": "2",
"desc": "two",
"sublist": [
{
"name": "wow",
"value": "80"
},
{
"name": "more wow",
"value": "60"
}
]
}
]
}
But I cannot use correctly jquerymy with a "simpler" version
"parent": [
{
"name": "1",
"desc": "one",
"sublist": [
{
"name": "wow",
"value": "80"
},
{
"name": "more wow",
"value": "60"
}
]
},
{
"name": "2",
"desc": "two",
"sublist": [
{
"name": "wow",
"value": "80"
},
{
"name": "more wow",
"value": "60"
}
]
}
]
I tried a couple of things in the manifest. I read the docs about this but I feel guilty I didnt' get how to do it.
I am probably just blind and not able to see something supersimple, what am I missing?
PS: TY for fixing so quickly the other problem.
Hi,
When I add your js file, It gives an error like that.
Uncaught TypeError: isS is not a function.
Thanks.
Hi Ermouth,
First of all thank you for you Jquery plugin. It is very useful for my side project :-)
I have two questions:
Is it possible to avoid the validation at the first loading of the form? Currently, empty fields that are required are in error when I display my form the very first time.
More a technical question. I created a class where I gather all the validation methods :
function Validator() {
this.allowEmptyField = true;
}
Validator.prototype.checkNotEmpty = function(data, val, $field) {
if (!val || val.length === 0) {
return this.allowEmptyField ? '' : 'Mandatoty field';
}
return '';
};
...
In my code I use this class as below:
this.validator = new Validator();
$('#formId').my({
...
ui: {
...
check: this.validator.checkNotEmpty
...
}
...
});
Later in the code, after a validation initiated by the end-user, I set the allowEmptyField to false:
this.validator.allowEmptyField = false;
Normaly, if the form validation calls again the checkNotEmpty method the allowEmptyField attribute should be false but... it is not. Unfortunately, this.allowEmptyField is not defined in the context of call of the method by the jquerymy plugin.
So how I can set the context of my Validator class?
I saw that the call is done from here https://github.com/ermouth/jQuery.my/blob/master/jquerymy.js#l1180 ?
Thanks again for your jquery plugin. Nice job!
Camel
Seems like JqueryMy uses .size() property.
But in jQuery 3.0 it has been removed (it was deprecated since 1.8)
https://api.jquery.com/size/
I simply tried removing (find-replace) $o.size() with $o.length and it seems to work.
But I'm not at all into jquerymy so I suppose we need more tests.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.