I'm new to JavaScript, focusing primarily on Java/PHP development. The JS applications I've built in the past have been pretty hackish, untestable, and unextensible.
I'm now trying to create an application that interfaces with data in a more appropriate manner. Basically I'm building a user interface for creating rules/actions that our support team and end users can access. The logic for the application contains a lot of Boolean and logical operators and just requires that some arbitrary set of conditions be met, and then will apply certain actions.
So, I've pretty much settled on a query builder type of application, and I love Mistic's work. Unfortunately, we don't have a Node.js server. So, I've set about finding ways to make this work with vanilla JS/jQuery. One iteration used Knockout.js. However, I found that API to be difficult to work with.
Now, I found this JSFiddle, which uses Mistic's work in a standalone version. I'd prefer to use this, but one thing I can't quite piece together is how to create multiple Query Builders dynamically. (Rules will appear in a table as shown in the second link, and I'll need an Add Row button).
$('#builder').queryBuilder({
sortable: true,
filters: [{
id: 'core_ID',
I've tried using the jQuery .each() function to create query builders bound to each element with a class of builder, but to no avail.
$.each('.builder').queryBuilder({
Can you guys show me how you'd go about dynamically creating new QueryBuilder objects as shown in the third link?
You use .builder as a selector, which means you select all elements that have a class="builder" attribute.
If that is so, then you should be able to just call $('.builder').queryBuilder(... and it should use all elements that have the class builder
EDIT: It does in fact do so. But the cakephp query builder doesn't allow it (for whatever reason). So you have to use each in the way that i describe.
if you want to use the each function, you would to it like that:
$( ".builder" ).each(function() {
$( this ).queryBuilder(...);
});
Explanation:
$(".builder") selects all elements that have a class="builder" attribute.
.each iterates over those elements. inside the function that is passed to each this contains the native DomElement (which is not a jquery element). Therefore $(this) gets the jQuery element for the DomElement and .queryBuilder is called on it.
you can call .queryBuilder on pretty much any jQuery element unless it is an array of elements (it will throw an error).
so basically any selector + each in the way I use it should work.
here is a working fiddle with your example using 4 querybuilders: http://jsfiddle.net/ap9gxo4L/42/
Related
I'm using Approval Tests and WatiN to test the integration of my ASP.NET MVC2 pages. WatiN launches IE to hit the given URL and then gives me the browser's html response in a variable. Then, Approval Tests allow me to compare the html response with an "approved" version of the html response. This system works great except that something (either IE or JQuery) is adding an unexpected attribute to my element.
Here's a copy of the form tag from IE's html response:
<FORM method=post action=/Account/LogOn jQuery1314030136323="2">
Notice the jQuery1314... attribute in the form element. It is always set to "2", but the name of the attribute is always different (jQuery###########). Since it's different every time, my Approval Tests fail. I need to either run a regex on the html output and remove the param with brute force, find a way to make the attribute name the same every time, or remove is altogether. Any ideas?
I'm intentionally -not- tagging this with ASP.NET because I really think this is specific to IE or JQuery.
That's the uuid/jQuery.expando that jQuery adds to every DOM element it interacts with, to work around browser memory leaks.
Older style code waited for window.onunload to unbind Javascript data from DOM tags to prevent memory leaks. JQuery avoids this by using a simple number (like the one in your code example) in an attribute and then keeping a hashmap in Javascript of tags and numbers (which it calls the uuid).
The weird attribute name is the value of jQuery.expando, which you can search for easily in the code and see it's set to a random value each time. This is done to allow multiple copies of jQuery to coexist on the page without interfering with each other.
I'm not aware of a use case I've ever needed where I need more than one jQuery on the same page, and I suspect you don't need this functionality either - you could easily resolve this by just eliminating this feature. Modify the code to set jQuery.expando to some hard-coded value, like 'jquery', instead of a random number, and you're good to go.
Be careful not to ever use jQuery twice in the same page though! Although doing so by accident introduces a lot of other strange side effects as well (like reuse of $), so that point may be moot.
I go into a little more detail about jQuery.expando/uuid in this question:
Why Doesn't JQuery Expose its UUID Functionality?
You'll notice in that write-up that the value of the attribute is random-ish - it's a counter based on how many tags have been interacted with by jQuery so far. If your code requires the attribute value to be consistent, you may still run into trouble.
Update
You'll need to modify your jquery source. For example, 1.6.2:
http://code.jquery.com/jquery-1.6.2.js
Includes the following:
jQuery.extend({
cache: {},
// Please use with caution
uuid: 0,
// Unique for each copy of jQuery on the page
// Non-digits removed to match rinlinejQuery
expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
You can change the expando line as follows:
// Does not support multiple copies of jQuery on the same page!
// 0 included to match rinlinejQuery (/jQuery\d+/)
expando: "jQuery0",
I believe it is what jQuery does internally to track all of the elements in the DOM that you have jQuery events wired up for. You might not be able to remove them without unhooking the events.
As a new web developer, I've been utilizing a lot of resources like StackOverflow to assist me in the learning and development process.
When using jQuery, all of the examples/responses that I've come across so far have only referenced classes, like so:
$('.yourClass')
as opposed to
$('#yourID')
Seeing that class referencing seems to be the trend (I honestly haven't found one author who writes a jQuery to an ID), are there any pitfalls I should be aware of for using ID's w/ jQuery or JS in general? Thanks!
EDIT 1: I'm aware that ID's are for single-items, classes are for accessing multiple items. I'm more interested in why I don't see any jQuery or JS examples referencing ID's. Thank you!
You would have to ask each author on a case-by-case basis, but generally when creating examples, the selector used doesn't matter; what's important is that you have a jQuery collection that you can call a method on.
By using a class selector in the example, you avoid newbie developers claiming that your plugin doesn't work when they try to use it on multiple elements with the same ID. Your example serves the purpose of showing how to use it on one or more elements, rather than just one.
People like to use classes because ids have to be unique across the whole page. When trying to make reusable, pluggable components, id's make this impossible to enforce.
Exception: the new web-components standard allows you to encapsulate ids to just your component.
An ID must be unique, you can have only one (like highlanders).
Classes are used to identify a "type" of object not a specific one.
An obligatory car analogy:
An ID is a license plate, unique to one specific thing #345-abc
The class relates to a whole category of things like .truck
Take note that a selector like $(".something") will actually be capable of producing a list of DOM elements; as it will select all DOM elements with the class of "something"
An ID selector $("#unique") will only ever return one element
Think of your HTML and CSS first.
Using Classes
If you have multiple HTML elements which all will look, feel and behave in the same way, then it is highly recommended to use a class to represent their style and behavior.
Example: rows or columns on a table, navigation buttons which animate in the exact same way, wrapper to images which have the same size throughout your website, etc.
Using ID's
However, if you have a unique HTML element which represents a particular thing or state or action in one of your pages, then that element should contain an id.
Example: pop up modal, a unique looking button, unique sections on your website which you can navigate to by their id, etc.
Then, you can use this behavior in your JavaScript and jQuery or whatever else you like to use.
Further reading
I know that you are fully aware of why we should use ID's or classes.
But the vast majority of answers that are given here, are thinking of a project context.
So, let's say editing a .js file that is linked to the scope of the entire project, the idea here is to be as reusable as possible, so that's why you'll see much more classes references than ID's. Is hard to maintain a project js file that makes reference to different ID's that are abroad the project.
Same thing will apply to css.
I hope the answer is enough, be free to post a comment or suggestions. :-)
I've had this happen to me three times now and I feel it's time I learned how to avoid this scenario.
Typically, I build the HTML. Once I'm content with the structure and visual design, I start using jQuery to wire up events and other things.
Thing is, sometimes the client wants a small change or even a medium change that requires me to change the HTML, and this causes my javascript code to break because it depends on HTML selectors that no longer exist.
How can I avoid digging myself into this hole every time I create a website? Any articles I should read?
Make your selectors less brittle.
Don't use a selector by index, next sibling, immediate child, or the like
Use classes so even if you have to change the tag name and the element's position in the HTML, the selector will still work
Don't use parent() or child() without specifying a selector. Make sure you look for a parent or child with a specific class
Sometimes, depending on the amount of rework, you'll have to update the script. Keep them as decoupled as possible, but there's always some coupling, it's the interface between script and HTML. It's like being able to change an implementation without having to change the interface. Sometimes you need new behavior that needs a new interface.
I think the best way to help you is for you to show a small sample of a change in the HTML that required a change to your jQuery code. We could then show you how to minimize changes to JS as you update the HTML
Lately I've been writing more and more JavaScript for the websites I've been creating. And I can't help but think that I'm doing something wrong, or there has to be a better way.
I have a clean separation of concerns on the server side, but on the client side, I find myself having entire sections of JavaScript that are dependent on specific element id's and class names, etc. For example, on one page, that has a lot of form fields, I may have a section of code that looks like:
$(document).ready(function() {
$("#ButtonID1").button();
$("#Grid").someGridFunction();
$(".data-fields").datepicker();
$(".submit-links").click(function() { this.closest("form").submit(); });
});
What I'd almost prefer is some way for the HTML elements to request to obtain certain functionality. Something like:
<input type="text" data-make="datepicker" />
But even that is flawed, because customization of that would require more and more attributes on the HTML element to detail specifics. I had a similar setup done with KnockoutJS and I really wasn't happy with the HTML that was required.
Maybe something along the lines of this:
<input type="text" data-init="buildDefaultDatePicker" />
where "buildDefaultDatePicker" is a JavaScript function that handles the necessary work.
In the end, the question I have is two fold. Is there any value in separating the JavaScript from the UI in regards to specific element ids and class names. And if so, what patterns, and or methods have you used to achieve this?
(Note, I'm using jQuery syntax above, but I think this question is framework agnostic, so shouldn't matter for the answers)
It looks to me like you've got the right idea already (using classes to apply JavaScript enhancement to specific elements). Using a custom attribute such as data-make or data-init would be just another (more fiddly) way of doing the same thing. The way you have things already, specific classes can be used as the request to obtain certain functionality.
The method I'd advise is keeping a clean separation between your HTML and JavaScript. The JavaScript should always be in external files, and written to target page elements on $(document).ready to provide the requested functionality.
I'd just use a class to signify the elements you want to attach behavior to. It has a semantic meaning, and you aren't coupling the html IDs or their locations into the javascript.
In the likely event that you need some specifics, like say a minimum or maximum date on a date picker, a light sprinkling of data attributes I think is an elegant way to provide it. But anything that would require more than a few data attributes is probably, in reality, a whole new kind of thing that deserves its own class, thus removing the need for the data attributes. For example, you might have a datepicker class, and find yourself constantly providing a minimum date of today to force a future date selection. Well, just make a 'futuredatepicker' class instead.
I find the the Django Admin's default models.ManyToManyField widget to be cumbersome to use. It's the HTML select element and if you have a lot of Objects of the "other" model then it's quite impractical to actually find the "other" Objects you want to associate with "this" Object. And if you have a lot of objects of the "other" model it seems to even slows down the rendering of the Admin page.
I'm aware that I can build my own custom admin widget and apply it to my ManyToManyFields as I see fit, but are there any pre-built ones out there that I might use instead? In my dreams, I picture an auto-completing text input HTML widget. Is this even practical/possible to do in the Django admin framework?
Thanks.
Try using the filter_horizontal attribute on your admin class, for example:
class SomeModelAdmin(admin.ModelAdmin):
filter_horizontal = ('users',)
As mentioned in the documentation, "adding a ManyToManyField to this list will instead use a nifty unobtrusive JavaScript "filter" interface that allows searching within the options". filter_vertical does the same thing with a slightly different layout.
you could try using a raw id in the admin.
and the django docs:
http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields
if you are looking for something with auto-complete you might want to look at this as a starting point http://code.djangoproject.com/wiki/AutoCompleteSolutions
and finally a very simplistic inline Example:
models.py
class SomeModel(models.Model):
users = models.ManyToMany(User)
admin.py:
class SomeModelAdmin(admin.ModelAdmin):
raw_id_fields = ("users",)
I haven't actually played with it but I found this promising looking library referenced elsewhere.
It appears to do exactly what I wanted. Rather than loading the entire list of related objects (regardless of how many there are!) and presenting you with a picker to select a few of them, as filter_horizontal does, it presents a search/filter box and uses typeahead/autocomplete calls to retrieve results dynamically. This is great for the case where you have maybe 5000 users and want to pick 3 or 4 of them without waiting for 5k <option> elements to download and render.
This is an old question, but I want to add an answer here for people who find this just like I did: this situation is exactly what Django inline admins are for. Specifically, I use TabularInlines with raw id fields for many-to-many relations that have too many choices.
https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#django.contrib.admin.TabularInline
You can try using Inline model as such -
class ManyToManyInline(TabularInline):
model = MyModel.many_to_many_field_name.through
raw_id_fields = ("render_raw_id_using_this",)
#register(MyModel)
class YourAdminClass(AnyBaseClass):
exclude = ("many_to_many_field_name",)
inlines = (ManyToManyInline,)
Now there is another issue I faced, finding "render_raw_id_using_this" field name.
So, I moved to shell and tried finding fields in through model as such -
In [1]: MyModel.many_to_many_field_name.through._meta.fields
Out [1]: (<django.db.models.fields.AutoField: id>, <django.db.models.fields.related.ForeignKey: fieldname1>, <django.db.models.fields.related.ForeignKey: fieldname2>)
So, I replaced render_raw_id_using_this with fieldname1
Similarly, you can use these field names to render raw id instead of drop down list in Inline model.