I am trying to use the accepts_nested_attributes_for method based on the tutorial by Ryan Bates ( http://railscasts.com/episodes/196-nested-model-form-part-1 ).
For my form, however, I want to have a select list made up of the child elements so that the parent form has a list of children. I then want to dynamically add children and populate them to the select box via ajax. I want those children to be created even if the form submit is aborted.
question - is this possible?
thanks!
EDIT: I have the form populating with the children in the select already. The question is really whether the ajax portion will work. Is it possible to submit just a portion of a form?
Turns out I ended up using the jquery autocomplete combobox (http://jqueryui.com/demos/autocomplete/#combobox) with some modifications. Specifically, the change: function listed looks for invalid selections (which is our case if the user types into the combobox). Here's the default code from the widget:
...
change: function( event, ui ) {
if ( !ui.item ) {
...
});
if ( !valid ) {
// remove invalid value, as it didn't match anything
$( this ).val( "" );
select.val( "" );
input.data( "autocomplete" ).term = "";
return false;
}
}
}
...
and I changed it to:
...
change: function( event, ui ) {
if ( !ui.item ) {
...
});
if ( !valid ) {
var _new_text = $(this).val()
var _new_option = '<option value="'+_new_text+'">' + _new_text + '</option>'
select.prepend(_new_option);//append to combobox
//now let's select it for submission
select.children( "option" ).each(function(){
if( $(this).text().match(_new_text) ){
this.selected = true;
return false;
}
})
}
}
}
...
Not sure if there's a better way to do it, but this is where I'm at now! Now working on the filtering of the content in Rails, but that's another story.
Related
I am working on a polymer2 shadow dom template project need to select children elements from parent elements. I found this article introduces a way to select child shadow dom elements that like this:
// No fun.
document.querySelector('x-tabs').shadowRoot
.querySelector('x-panel').shadowRoot
.querySelector('#foo');
// Fun.
document.querySelector('x-tabs::shadow x-panel::shadow #foo');
However, when I tried in my polymer2 project, like this:
//First: works!!
document.querySelector('container')
.shadowRoot.querySelector('app-grid')
.shadowRoot.querySelector('#apps');
//Second: Doesn't work!// got null
document.querySelector('container::shadow app-grid::shadow #apps')
// Thrird: document.querySelector('* /deep/ #apps') // Doesn't work, got null
I really need the second way or the third, which to put selectors in (), but both couldn't work. Does anyone know why the second one doesn't work? Thank you so much!
::shadow and /deep/ has never(?) worked in Firefox, and is depraved in Chrome 63 and later.
Source
Eric Biedelman has written a nice querySelector method for finding all custom elements on a page using shadow DOM. I wouldn't use it myself, but I have implemented it so I can "querySelect" custom elements in the console. Here is his modified code:
// EXAMPLES
// findCustomElement('app-grid') // Returns app-grid element
// findCustomElements('dom-if') // Returns an array of dom-if elements (if there are several ones)
// findCustomElement('app-grid').props // Returns properties of the app-grid element
function findCustomElement(customElementName) {
const allCustomElements = [];
customElementName = (customElementName) ? customElementName.toLowerCase() : customElementName;
function isCustomElement(el) {
const isAttr = el.getAttribute('is');
// Check for <super-button> and <button is="super-button">.
return el.localName.includes('-') || isAttr && isAttr.includes('-');
}
function findAllCustomElements(nodes) {
for (let i = 0, el; el = nodes[i]; ++i) {
if (isCustomElement(el)) {
el.props = el.__data__ || el.__data || "Doesn't have any properties";
if (customElementName && customElementName === el.tagName.toLowerCase()) {
allCustomElements.push(el);
} else if (!customElementName) {
allCustomElements.push(el);
}
}
// If the element has shadow DOM, dig deeper.
if (el.shadowRoot) {
findAllCustomElements(el.shadowRoot.querySelectorAll('*'));
}
}
}
findAllCustomElements(document.querySelectorAll('*'));
if (allCustomElements.length < 2) {
return allCustomElements[0] || customElementName + " not found";
} else if (customElementName) {
allCustomElements.props = "Several elements found of type " + customElementName;
}
return allCustomElements;
}
Remove the if (isCustomElement(el)) { statement, and you can querySelect whatever element and get an array of it if several of them exists. You can change findAllCustomElements to implement a smarter querySelect using the recursive loop on shadowDoom as base. Again, I wouldn't use this myself – and instead pass on variables from parent element(s) to children where the children have observers that activates specific behaviors – but I wanted to give you a general implementation of a fallback if nothing else works.
The problem with your question is that you don't give any specifics about WHY you want to select the children in the first place.
I am using Odoo 10e. I want a simple functionality that whenever i wanted to delete one or more then one item from a list view or from a specific list view only. I want to show all of the items which are selected for deleted to show their name in popup window so that user can have a quick review what's he is going to delete. I know user can see details in list view but i want to give a glimpse to user in shape of model window that this is going to be deleted. Are you sure to delete ?
If user click Confirm then normal delete case should work.
As far i research and worked on it, i have idea that it should be something regarding overriding the do_delete method in the list_view.js in the web module. But i didn't know much about javascript overriding for Odoo.
This is an example how I do it.
I called the name_get for your model and records ids, this names list, I change the text of confirming message with the information of ids selected.
do_delete: function (ids) {
new Model(this.model)
.call('name_get', [ids, this.dataset.get_context()]).done(function (names) {
var text = _t("Do you really want to remove these records?") + ' '+ names.join(' \n')
if (!(ids.length && confirm(text))) {
return;
}
var self = this;
return $.when(this.dataset.unlink(ids)).done(function () {
_(ids).each(function (id) {
self.records.remove(self.records.get(id));
});
// Hide the table if there is no more record in the dataset
if (self.display_nocontent_helper()) {
self.no_result();
} else {
if (self.records.length && self.current_min === 1) {
// Reload the list view if we delete all the records of the first page
self.reload();
} else if (self.records.length && self.dataset.size() > 0) {
// Load previous page if the current one is empty
self.pager.previous();
}
// Reload the list view if we are not on the last page
if (self.current_min + self._limit - 1 < self.dataset.size()) {
self.reload();
}
}
self.update_pager(self.dataset);
self.compute_aggregates();
});
});;
},
I have a large Dijit-based form with many Dijits in collapsible TitlePanes.
When the form validates, any invalid items hidden inside closed TitlePanes (obviously) cannot be seen. So it appears as though the form is just dead and won't submit, though, unbeknownst to the user, there's actually an error hidden in a closed TitlePane which is preventing the form processing.
What's the solution here? Is there an easy way to simply open all TitlePanes containing Dijits that are in an error state?
If validation is done by following, it will work:-
function validateForm() {
var myform = dijit.byId("myform");
myform.connectChildren();
var isValid = myform.validate();
var errorFields = dojo.query(".dijitError");
errorFields.forEach(fieldnode){
var titlePane = getParentTitlePane(fieldnode);
//write a method getParentTitlePane to find the pane to which this field belongs
if(titlePane) {
titlePane.set('open',true);
}
}
return isValid;
}
function getParentTitlePane(fieldnode) {
var titlePane;
//dijitTitlePane is the class of TitlePane widget
while(fieldnode && fieldnode.className!="dijitTitlePane") {
fieldnode= fieldnode.parentNode;
}
if(fieldnode) {
mynode = dijit.getEnclosingWidget(fieldnode);
}
return titlePane;
}
Lets say if the following is the HTML and we call the above validateForm on submit of form.
<form id="myform" data-dojo-type="dijit/form/Form" onSubmit="validateForm();">
......
</form>
Here's what I ended up doing (I'm not great with Javascript, so this might sucked, but it works -- suggestions for improvement are appreciated):
function openTitlePanes(form) {
// Iterate through the child widgets of the form
dijit.registry.findWidgets(document.getElementById(form.id)).forEach(function(item) {
// Is this a title pane?
if (item.baseClass == 'dijitTitlePane') {
// Iterate the children of this title pane
dijit.registry.findWidgets(document.getElementById(item.id)).forEach(function(child) {
// Does this child have a validator, and -- if so -- is it valid?
if (!(typeof child.isValid === 'undefined') && !child.isValid()) {
// It's not valid, make sure the title pane is open
item.set('open', true);
}
});
}
});
}
I have Problem with Store in ExtJS 4. In my application I want to use two combo. A store values are displaying in both combo. But the problem is the value selected in first combo should not get shown in next combo. Due to single store I'm unable to make it happen..What should have to do ?
This Works for me
listeners : {
expand: function() {
boxerListStore.filter(function(r) {
var value = r.get('id');
var getValue = Ext.getCmp('boxer2').getValue();
return (value != getValue);
});
}
}
You can use select event of first combo like -
listeners: {
select: function(combo, records, eOpts){
Ext.getCmp('secondCombo').select(records[0]);
}
}
In one of my projects I use a dijit.Tree control. I need to add a search to the tree and show only those nodes/leafs which have the searched term in them. However I can't seem to figure out how that can be achieved. Could anybody please help me?
im not entirely sure that your question entirely but it should give hint whereas to go.
Lets use reference documentation example as offset, there is 1) a store 2) a model and 3) the tree
var store = new ItemFileReadStore({
url: "{{dataUrl}}/dijit/tests/_data/countries.json"
});
var treeModel = new ForestStoreModel({
store: store,
query: {"type": "continent"}, // note, this bit
rootId: "root",
rootLabel: "Continents",
childrenAttrs: ["children"]
});
new Tree({
model: treeModel
}, "treeOne");
Interpret the above as such; You have loaded all known countries and continents but 'user' has selected only to show continents by using query on the model - and the hierachy is then represented in a tree structure.
You want a textbox with searching capeabilities, so we hook into onChange
new dijit.form.TextBox({
onChange: function() {
...
}
});
First bit, getting variables
var searchByName = this.get("value");
var oQuery = treeModel.query;
Next, set a new query on the model - preserving the old ones with an object mixin
treeModel.query = dojo.mixin(oQuery, { name: '*'+searchByName+'*' });
Last, notify the model and its tree that changes has occurred - and requery the visible items.
treeModel._requeryTop();
NB If the top-level item (for ForestModel) is not visible, none of its child elements will show, even if the search-string matches those. (Examplewise, Alabama is not shown if US Continent is not matched by query)
EDIT
As OP has the agenda to go by the 'NB', this may not fit needs 100% but its what dojo offers with dijit.Tree.. As it will get rather a lengthy process to recode the model/store queries to include parentbranches up until root i will not do this here - but there are a few tricks still ;)
var tree = new dijit.Tree( {
/**
* Since TreeNode has a getParent() method, this abstraction could be useful
* It sets the dijit.reqistry id into the item-data, so one l8r can get parent items
* which otherwise only can be found by iterating everything in store, looking for item in the parent.children
*
*/
onLoad : function() {
this.forAllNodes(function(node) {
// TreeNode.item <-- > store.items hookup
node.item._NID = node.domNode.id
});
},
/* recursive iteration over TreeNode's
* Carefull, not to make (too many) recursive calls in the callback function..
* fun_ptr : function(TreeNode) { ... }
*/
forAllNodes : function(parentTreeNode, fun_ptr) {
parentTreeNode.getChildren().forEach(function(n) {
fun_ptr(n);
if(n.item.children) {
n.tree.forAllNodes(fun_ptr);
}
})
}
});
(non-tested, but might just work) Example:
// var 'tree' is your tree, extended with
tree.forAllNodes = function(parentTreeNode, fun_ptr) {
parentTreeNode.getChildren().forEach(function(n) {
fun_ptr(n);
if(n.item.children) {
n.tree.forAllNodes(fun_ptr);
}
})
};
// before anything, but the 'match-all' query, run this once
tree.forAllNodes(tree.rootNode, function(node) {
// TreeNode.item <-- > store.items hookup
node.item._NID = node.domNode.id
});
// hopefully, this in end contains top-level items
var branchesToShow = []
// run fetch every search (TextBox.onChange) with value in query
tree.model.store.fetch(query:{name:'Abc*'}, onComplete(function(items) {
var TreeNode = null;
dojo.forEach(items, function(item) {
TreeNode = dijit.byId(item._NID+'');
while(TreeNode.getParent()
&& typeof TreeNode.getParent().item._RI == 'undefined') {
TreeNode = TreeNode.getParent();
}
branchesToShow.push(TreeNode.item);
});
}});
// Now... If a success, try updating the model via following
tree.model.onChildrenChange(tree.model.root, branchesToShow);