K2 Smartforms Only Execute Action if Sub View/Form Not Open - k2

I have a K2 SmartForm (v4.7) with a list view, and a timer that refreshes the data in that view. However when a subform (or subview) is open on top of the base form and the timer ticks, the "loading" indicator and white box covers up the entry form while the list is being refreshed.
Is there a way to either have the loading panel display under the subform, or a way to apply a rule to the timer's tick event to check if a subform is open?
I realize it's possible to have a rule stop the timer when the subform opens, and start it again when it closes, but there are multiple subforms and views that can be displayed in this app and it would be much easier to simply have the timer tick event check if anything is open.

Ok, so here's some JavaScript magic, #nigel-whatling:
I've added a checkbox control to the form called ckIsSubOpen. Then on the timer's tick event I'm passing some javascript into a data label (literal) which will call a function (set on the view initialized event) to set the control value. Then the next action in the rule checks if that checkbox is checked, and if its value is false, will run the refresh command.
This got tricky because you can't simply manipulate DOM elements and have K2 pick up the value change. According to this thread there's an XML document stored as a page variable, along with a handy function to manipulate the values:
function customUpdateSfControl(controlName, value) {
var myTextBoxXPath = 'Controllers/Controller/Controls/Control[#Name=\"' + controlName + '\"]';
var windowToUse = window;
if (!checkExists(windowToUse.viewControllerDefinition)) {
windowToUse.viewControllerDefinition = $xml(windowToUse.__runtimeControllersDefinition);
}
var myControl = windowToUse.$sn(windowToUse.viewControllerDefinition, myTextBoxXPath);
var controlInfoObj = new windowToUse.PopulateObject(null, value, myControl.getAttribute('ID'));
windowToUse.executeControlFunction(myControl, 'SetValue', controlInfoObj);
windowToUse.raiseEvent(myControl.getAttribute('ID'), 'Control', 'OnChange');
}
The script which sets the field value checks for any divs that have the sub-form or sub-view class:
customUpdateSfControl('ckIsSubOpen', ($('div.sub-view, div.sub-form').length > 0));
This seems to work for my needs.

You can set rules on subview and subform events such as Initialize and also when they close. You could do your tracking with those. But you'll still have to do it for every subview/subform.
Other than that, I think you'd have to do some JavaScript magic.

Related

Execute query on active region

I have one page where i have about 8 tab region. Each region has a select statment. They are executed when accessing the page (page load) at the same time. Because i have 8 select statment that executes at same time it leads to pure performance.
My question is how to execute the query only on active region.
You can try this one
Create Dynamic Action on event "Page Load"
Create true action "Execute javaScript Code":
window.setTimeout(function(){
$('.a-Region-carouselLink').click(function(){
apex.event.trigger(document, 'tabChanged', this);
})
}, 500);
Set "Fire On Page Load" to "Yes"
Create Custom event "tabChanged"
Create true action in DA custom event "Execute JavaScript Code":
console.log(this.data);
Test it - each time you click the tab, DA prints to console currently clicked anchor.
Of course it is not perfect because of the 0.5s delay. Still it allows you to listen what tab was "clicked".
To make your scenario work I would do:
create page item PX_TAB
create true action in custom event to set value of PX_TAB
create true actions in custom event to refresh reports within tabs
set "Page Items to Submit" to "PX_TAB" in each report to be refreshed
add condition to each report comparing value of item PX_TAB - it will execute SQL query only when PX_TAB has expected value
edit 2016.08.13
You can bind tabs by simple adding listener to the tabs
$(document).on('mousedown', 'a.t-Tabs-link', function(){
//this is an anchor used as tab
console.log(this)
})
If you want to keep it in APEX way enter code from below in Execute when Page Loads page section or create new dynamic action On page load
$(document).on('mousedown', 'a.t-Tabs-link', function(){
apex.event.trigger(document,'tabChanged', this);
})
and then add dynamic action bound to Custom event named tabChanged. Whenever tab is clicked the tabChanged event is triggered, and in Execute JavaScript Code you can reference current tab by this.data
Try to create buttons and set behavior of each button to display required region and hide others (create hidden item, then create buttons that set values 1,2,3 etc., then add conditions to every region to display region 1 only when hidden item equal 1, region 2 for item value 2 etc.

ember component is passing param by reference in {{#each}}

It may help to follow along with this CodePen. Click the icons.
I have a list of items, each rendered using the ItemIndexComponent, which has a property, controls, that is an array of objects, each of which describes an icon to display, action to be taken, and a state (true/false). The idea is that the controls are passed into a configurable ToolboxMenuComponent that doesn't have any logic about what actions to perform nor icons to display. It receives a click from its child component, which passes up the corresponding control object.
The toolbox then toggles the state on the control before passing that, along with the item, further up the chain to the ItemIndexComponent. Which then examines the control to see which property to change on the item. That all works great, except ...
The problem I'm having is that the same controls array is passed to each item. So, if I click on the edit icon, the "editing" property on that item changes -- colour turns green. But when I click the edit icon for any other item, nothing happens because the "edit" control state is already true, is subsequently toggled, then sent up the chain, resulting in no change to the second item, whose state is already false. If I click the second item's icon again it changes, of course, because the state had previously been toggled.
I understand what's happening but I'm buggered to figure out how to handle this with Ember. How can I pass each item its own controls array whilst keeping the Toolbox agnostic? That is, I want it to know only that controls has those three properties, that state should be toggled, and that it should pass back item and not know anything about item nor toggle the item properties itself. But each item should have its own controls and thus mind its own state for each control.
I swear, every time I post to SO, it's after hours of futility. Then, while putting together the question I go through a half-dozen attempts. And then I post, and the solution bangs me square between the eyes.
Because ToolboxMenu already knows about the state property there's no harm in using that. The answer was to set an instance property on the child ToolboxMenuItem based on controls.state, then toggle that and pass that up the chain. Now, controls.state becomes defaultState, is used precisely once and then ignored. Only the action need be passed up, not the entire control object.
(I had to use mode as the child component property because Ember was complaining about a deprecated state member.)
App.ToolboxMenuComponent = Ember.Component.extend({
actions: {
toggleTool: function(action, mode) {
this.sendAction("action", this.get("item"), action, mode);
}
}
});
App.ToolboxMenuItemComponent = Ember.Component.extend({
mode: null,
didInsertElement: function() {
this.set("mode", this.get("control").defaultState);
},
actions: {
click: function() {
let mode = this.get("mode");
this.set("mode", !mode);
this.sendAction("action", this.get("control").action, this.get("mode"));
}
}
});

disconnect dojo event of datetimebox

I wanted to disconnect event of datetimebox (_onBlur). It is mentioned in the file "TextBox.js". 'dojo.disconnect' works on custom events that I define in my javascript. But i want to do the same for the dojo widget itself. I cannot disconnect events declared (_onBlur) in the dojo widget(Textbox.js).
Below is declaration in the Textbox.js widget.. how should i declare disconnect event that below event is never call ???.. again below code is from widget & it is not my code.. using dojo.disconnect i am able to disconnect events declared in my custom js file but I m not able to disconnect events such as below declared in widget js file that comes with dojo library.. please suggest
_onBlur: function(e){
this._setBlurValue();
this.inherited(arguments);
if(this._selectOnClickHandle){
this.disconnect(this._selectOnClickHandle);
}
if(this.selectOnClick && dojo.isMoz){
this.textbox.selectionStart = this.textbox.selectionEnd = undefined; // clear selection so that the next mouse click doesn't reselect
}
this._updatePlaceHolder();
},
Simon, I want it because it is advantageous to have it when we want to override dojo inbuilt events with our own custom events. Example is when you use dojo grid and use arrow key (up, right, down..) the cell is highlighted (dotted line is surrounding the cell) indicating current cell ... now if you want to disable i.e keep the cell hghlighted for a while lets say you display edit/text on that cell you but if user again tries to press arrow key you will see the dotted line is still rotating around which you do not want... easiest is to disable/disconnect the event in this case event tied to grid is "doKeyEvent" which listens to key event and does the hghlgt of cell.. I have achieved this by keypress & other events to counteract or nullify what grid is doing but still.. easiest is to disable/disconnect this grid events itself & let concentrate on business events & logic reqd rather than try to code for events that are default to the dojo component which might be good for some business not for all .. this counter events has to be taken place for other components as well
Dojo disconnect will only work with events added by dojo.connect. I don't think you can do what it is ur trying to do. Why do u need to do this perhaps there's another way around ur issue?
As Simon pointed out Dojo disconnect will only work with events added by dojo.connect.
But a solution to your problem could be to override the onBlur() function so it will not execute, example:
this.onBlur = function(){
return false;
}

Handling Postback within a Webpart in Sharepoint

I am initializing a GridView, text box and a button via code to a Webpart in CreateChildControls()
The above controls are declared as class variables but initialized only later.
Next, I've given the handler for button click. The handler function is supposed to work as a search - perform some operations on the content entered in the textbox, load the results in the Gridview, display the Gridview
When I type something in the text box and hit the button, the same controls load again and the content entered in the text box is lost. I've tried ViewState() and ViewState() but to no avail. The grid doesn't show because my logic skips attempting to bind it since a proper search string was not available.
My questions:
1) Where/how can I get the values postback from the textbox?
2) Will it make sense to populate the GridView in PreRender() or will Event Handling happen after PreRender()?
EDIT:
Seems like the event handler is not getting called.
Dim btnClickHandler = New EventHandler(AddressOf SetSearchParameter)
AddHandler srchBtn.Click, btnClickHandler
is correct?
EDIT:
I redid all code from 0. Its working now.
you should be able to reference the control values in the event handler for the button click, depending on how to build them static/dynamic. (textbox)Page.FindControl('controlname').value in your event handler for the button click.
er... this.findcontrol.
im doing this from memory so syntax might be off.
This always confuses me too. I always reference this question in order to get it straight (also the control execution lifecycle).
You shouldn't need to manage viewstate, that should be taken care of automatically by your controls.
I would suggest using the OnPreRender to populate your grid. Your controls should have their values populated by the ViewState by then.

What is the best way to detect when a div changes width with jQuery?

I'm adjusting the width of a div using media queries. I need the page to react when that div changes width.
I've used .resize, however, that triggers twice and causes an issue when the user interacts with the div further. I can't use .live() since that requires the user to interact to achieve the desired effect. Finally, Ive looked into DOMSubtreeModified but that has been depreciated.
In simple terms this is what I want to do:
$('#element').watchForChange(function(){
*...do stuff here when the change happens...*
});
Thanks for your assistance.
----- EDIT -------
Let me clarify a common issue I see with resize with this example:
<div id="box"></div>
<span id="button">Open</span>
In the above example assume the #box is 400x400 and in the "open" state (display:block). When the window resizes to 800px I want the box to close (display:none). The "open" button will use jquery to open the box again ($('#button').click(function(){...});)
The issue I keep sing is when I would click "open" the box opens then closes. The second click works fine.
Jquery is retaining the second call in the event handler. I can't unbind it since I'll need to check the size again.
I'm not using an open close function. Rather I'm using a next button on a slider. I need the items to reset back to the beginning on that resize. I can get them to reset, no problem. The issue is: the second click of "next" resets it.
Using a technique found here:
JQuery: How to call RESIZE event only once it's FINISHED resizing?
http://jsfiddle.net/Zevan/c9UE5/1/
var id;
$('#element').resize(function() {
clearTimeout(id);
id = setTimeout(doneResizing, 500);
});
function doneResizing(){
// do something
console.log("done resizing");
}​
The event will still fire multiple times but the doneResizing function will only be called 500 milliseconds after the last one fires. Of course, you can adjust that number to suit your needs.
OK - based on your edited question, here's the issue. The toggle function is keeping track of which function it ran for last click and will always run the other function for the next click. So, when you click it once, it runs the first function, click again, it runs the second function, and then back to the first and so on.
But, your window resize event is collapsing the window, so if the last time you clicked your h1 was to expand it, then the next click, toggle will attempt to close it. So, your window resize event closed it and then the button is closing it again. That's why you don't see any results the first time you click the button after a window resize.
I modified your code to not use toggle -- and to use a state variable instead:
http://jsfiddle.net/SVy6m/1/
var target;
var isCollapsed = true;
$('h1').click(function() {
if(isCollapsed) {
$('.box-1').slideDown();
} else {
$('.box-1').slideUp();
}
isCollapsed = !isCollapsed;
});
var id;
$(window).resize(function() {
clearTimeout(id);
id = setTimeout(doneResizing, 10);
});
function doneResizing(){
// do something
$('.box-1').slideUp();
isCollapsed = true;
} ​
You'll still need to add some code to check if the window size is less than 800. Hope this helps!

Resources