Unable to call getValues() on an Ext Js FormPanel on initialization of a container Panel - forms

I have an Ext Js panel that I am adding to my main TabPanel. The panel I am adding contains a FormPanel as one of it's items and inside the FormPanel I have a Name field. What I want to do is change the name of the Tab based on the name in the form field.
The problem is that if I call the FormPanel's getForm().getValues() inside of the panel's initComponent, I get the following javascript error:
Uncaught TypeError: Cannot read property 'dom' of undefined
If I do this outside of initComponent (e.g. on a button press) everything works fine. After doing some testing, I think the issue is that the FormPanel isn't actually rendered yet (and thus the dom doesn't exist), getValues() fails. However, I can't seem to figure out a way to get my FormPanel's values from the Panel on load.
I tried to listen for events. I tried:
this.detailForm.on('afterrender', function () { alert('test'); });
but doing this showed that AfterRender is called prior to the form actually being rendered (it's not visible on the screen). Changing the alert to my custom function handler produces the previous dom exception. I attempted to use the activate and enable events instead of afterrender, but even though the API says that FormPanel fires those events, the alert('test') never gets called.
I can't seem to find any way for my panel to get the inner FormPanel's values upon loading my panel. Does anyone have any ideas?

Using getFieldValues() in place of getValues() will collect values by calling each field instance's getValue() method instead of by reading from the DOM. This should allow you to get your values regardless of the form's rendered state.

I've got the same problems on one of my projects, I managed to fix it using the afterlayout event.

I'd give setting .deferredRender:false a try.
Ext.TabPanel.deferredRender
Probably best to roll out of your afterlayout changes, then test with just a straight deferredRender:false config item.
I believe the problem is caused because the inactive tabs are not rendered until they become active. In your scenario, you cannot get the values, because they don't exist until the tab is activated/shown.
Setting deferredRender:false will render the items within all tabs. There could be a performance hit by setting deferredRender:false, so testing you must do.
Hope this helps.

Related

When does converse.js chatBoxInitialized event actually emit?

I'm trying to configure a few settings in a converse.js chatbox (title, removing avatar, chatbox width) PRIOR to it "rendering" and displaying the chatbox.
While not explicitly saying so, I had figured that the "chatBoxInitialized" event would fire AFTER the chatbox object was created, but prior to rendering and displaying.
What I'm finding is that when my handler function for that event is called, the chatbox is already displayed, so clearly my understanding of "chatboxinitialized" is incomplete. Inside the handler, I have used available methods in chatbox object such as
chatbox.setChatBoxWidth(350);
chatbox.model.attributes.fullname = data;
to set chatbox attributes but while the statements execute and have a momentary effect, as soon as the handler function completes, something is setting those values back, and the box "re-renders" and displays as it was before my function ran.
Is there a more appropriate event to register for so these values can be set prior to chatbox rendering? Are there more appropriate "chatbox set functions" that can be used to properly set such things as size, and turn off avatars, rather than just reaching into DOM directly and manipulating after the fact?
Any help would be appreciated.
If you look at the code, you'll see that chatBoxInitialized gets triggered after the chatbox's HTML has already been rendered.
See here: https://github.com/jcbrand/converse.js/blob/393bbe020e45ccd2abe10683117a8f854dea9145/src/converse-chatview.js#L281
Looking at the code, I don't see any event that's triggered after the chatbox has been created, but before it's rendered.
However, in the current master branch of converse.js (to be released soon), you can set the fullname after the chatbox has been created, and it will then appear properly.
You're however setting it wrong. With Backbone.js you must use get and set and not the attributes property.
So this:
chatbox.model.attributes.fullname = data;
must be changed to this:
chatbox.model.set({'fullname': data});
Concerning setting the chatbox width, I think the best way to do that is to set the relevant Sass variable, see here:
https://github.com/jcbrand/converse.js/blob/393bbe020e45ccd2abe10683117a8f854dea9145/sass/converse/_variables.scss#L111
Then run make css to generate new CSS.

mousedown event on options in select with jquery .on

I was reading the documentation of the .on event handler of jQuery and I started playing around with it.
I have a simple <select> element with the multiple attribute set to true.
However, I want the user to be able to select multiple items without having to press the ctrl or shift key(s)
According to the .on documentation, if you specify a selector it will automatically add those event handlers to any new items added inside that container that match the selector specified.
So in my case, I could for example decide to replace the <option> elements available in the listbox, but I still want to have the same functionality for those options without having to rebind those events etc.
One might think that the following snippet should do the trick (atleast, I did):
$('#dropdownlist').on('mousedown', 'option', function(e){
e.preventDefault();
$(this).prop('selected', $(this).prop('selected') ? false : true);
return false;
});
So when a users clicks on an option in that listbox, the default action will be cancelled and depending wether the item is already selected or not, it will invert that selection.
I have created a small fiddle demonstrating this behaviour: fiddle
In that fiddle, the first dropdownlist is behaving as expected, but the functionality is lost when replacing the items. This only works in FF & Chrome.
The second dropdownlist is how I thought it should've been (event handling wise), but that doesn't seem to work besides in Chrome -.-
The functionality is kept when replacing items, because the console will still log '2' when clicking on an item after replacing them.
Can someone explain me why this is happening? Am I doing something wrong?
Please point me in the right direction!
Thanks!
~ Dirk
IE doesn't respect the mousedown event on the option tag itself. You've got to use the OnChange event of the select tag, which is not what you (nor I) want. I was trying to do the exact same thing as you and was stopped at every attempt. I finally gave up and made it a list of checkboxes because I can get the same behavior out of mine that you are trying to do here.
You can see this question for some options, but I never did get it to work the way you are describing.

Setting values to a form which is not rendered yet

I have a form within a tab. It is second tab so it doesn't render until you open it.
I have tried to submit data to the form with Ext.getCmp('DetailsForm').getForm().setValues(selections[0]); but it says that it is not a function. Probably because it is not rendered yet. What I have to do?
Set the deferredRender config property of your Ext.tab.Panel to deferredRender: false
That will force the rendering of all tabs instead of just active ones. Now the form will be there. As mentioned before I recommend you also to use myTabPanelRef.down('from').getForm().setValues(selections[0]); to access the form.
subscribe to the second tabs show event OR painted event
then look for the form preferably by using .down() method as this wont look with in the entire DOM.
set the values
Use render event of form panel.
Your code will be something like this -
Ext.getCmp('DetailsForm').on('render', function(){
this.getForm().load(selections[0]);
});

jQuery Show/Hide divs using same class not working because of html.push?

The object is to Show-Hide text located under their respective Titles, so a User reads the title and shows or hides text belonging to that title if the User wants to read more.
I tried whatever I could find so far on here, we're talking dynamically setting text coming from a spreadsheet, can't use IDs, must work with .class, must be missing something, I have this piece of code:
... html.push('<div class="comments">' + comment + '</div></div></div>');
but when I try this Show-Hide code nothing happens, even if the error console shows nothing. Basically I want to Show-Hide the .comments class divs with a show-hide toggle link located under each of them. I say them because the .comments divs are reproduced dynamically while extracting text coming from Google spreadsheet cells/row (one .comments div per spreadsheet row). I tried .next, child and parent but they all divorced me so I dunno looks like a dynamic issue. So far I only managed to globally toggle all divs to a visible or hidden state but I need to toggle independantly individual divs.
I prefer a jQuery solution but whatever worked so far was achieved with native javascript.
Note: If a cross-browser truncate function which would append a more-less link after a number of words (var) in each .comments divs would be easier to implement then I would gladly take that option. Thx for any help, remember I am still learning lol!
I have been working on an entirely JS UI project and have brought myself to using $('', { properties }).appendTo(BaseElement) to work best for adding HTML elements because it appropriately manipulates the DOM every time.
If you are having good luck with push elsewhere, however, breakpointing on the line where you do your $('.class').hide() and see what $('.class').length is. Alternately, you can just add alert($('.class').length) to your code if you are unable to breakpoint the code. If it is 0, then your elements have not been properly added to the DOM. Changing to append will ensure they are part of the DOM and therefore targetable via JQuery.

WorkflowView force refresh when new child Activity is added

My application is using workflow designer rehosting to let end-users develop workflows. I have an Activity available that requires the user set some state. To accomplish this, in the designer I override Initialize(Activity) and show a form which I then use to set values in my Activity. This is for setting the state when the Activity is initially added. I also have a double click event handler in the designer in case they need to edit that state later.
I now have a situation where, depending on the values in the form, I may need to add or remove a child activity. I've been successful in adding the activity, but not always in getting it to show up in the designer.
When Initialize is called, there are no child activities. I may need to add a child Activity. At this point, it works fine and shows up in the designer. The problem happens when they edit it later by double clicking. In my designer, I override OnActivityChanged to detect this. I make the same call to add a child, however the designer is not getting updated. Oddly enough, when the situation is such that the child is removed, the view updates fine.
Stepping through with the debugger shows that I am adding a child activity to the Activities collection. Normally when I have problems updating the view, I can make a call to IComponentChangeService.OnComponentChanged, but I can't seem to find a way to make this work.
Any suggestions?
It looks like I needed to use RemoveActivities and InsertActivities in the designer. It seems as if the designer doesn't listen to list change events on the Activities list. Does anyone know if this is how it's supposed to work?
Have you tried this in your OnActivityChanged event handler?
TypeDescriptor.Refresh(e.Activity);
For my situation, I determined I needed to use RemoveActivities and InsertActivities.