My task: a dynamic progress bar in odoo.
I'm using the Odoo widget: 'progressbar'. I want to update the view every time the value is updated - hence I want to trigger the on_change_input javascript function inside my python write method to render the view.
#api.one
def updatevalue(self, val):
self.value = val
# TODO call javascript function on_change_input()
The purpose is, that the progressbar should be updated while a process is running and the user should see the progress without updating the site.
Is my task possible with the progressbar widget? Or is there another possibility to show dynamic content in Odoo?
If I use my updatevalue method as button, the progressbar is updated after clicking the button without calling the javascript function & without refreshing the page... but I do want to call the method in my code (and probably over rpc) therefore this does not help -.-
Thank you for your time!
Here is the workflow I have so far:
The user clicks on the button do_time_consuming_task
and the following function is called:
def do_timeconsuming_task(self):
ws = websocket.WebSocket()
ws.connect('ws:/129.0.0.1:1234/')
data = { 'topic' : 'server_command', 'id' : self.id, 'commandName' : 'do_sth',}
payload = ujson.dumps(data)
ws.send(payload)
ws.close()
On the server, the command is received and processed. There is an open rpc connection:
odoo = odoorpc.ODOO("129.0.0.1", port=8069)
odoo.login("database", "user", "password")
my_module = odoo.env['my_module.progress_widget_test']
progress_instance = my_module.browse(id)
Every time the progress value changes I call the following method of my module:
progress_instance.updatevalue(new_value)
when the value equals 100 % I close the connection
odoo.logout()
This functionality already exists and you can copy parts of it from account/static/src/js/account_reconciliation_widgets.js from the method updateProgressBar and processReconciliations. You will see here the correct way of updating the progress bar.
The purpose is, that the progressbar should be updated while a process
is running and the user should see the progress without updating the
site.
See on the processReconciliations how it is done, basically you call the process_reconciliations method that exists on the back end and you get a deferred object back. From that deferred object you can use progress()
Looking through the documentation of .progress() you will see that you need to report your progress using .[notify][2]()
How do you define the percentage of completion of your process?
Related
I have report view where a bunch of controls located, there is an example code:
#Html.DevExpress().DropDownEdit(
settings =>{
settings.Name = "SomeList";
settings.Width = 100;
settings.SetDropDownWindowTemplateContent(c =>{
#Html.DevExpress().ListBox(
...
).BindList(ViewData["SomeList"]).Render();
some code...
).GetHtml()
When it render first time it works fine, but in business logic there is another drop down let's call it dropdown #2. When user select some values in dropdown#2 JS handle this action send request to the server to get actual value for first dropdown, then clear all rendered values from dropdown #1 and insert new items.
And problem in performance lies in how devexpress create new items on client side. From backend there is now 8000 new items can be added to dropdown #1 and it keep growing. And user must wait 5-10 seconds when browser render it. I tried to research what is happening when new item is creating but there are a lot of devexpress function which call another functions.
JS code look's like:
SomeList.BeginUpdate();
l = data.SomeList.length;
while (x < l) {
SomeList.AddItem(data.SomeList[x].Name, data.SomeList[x].Id);
x++;
}
SomeList.EndUpdate();
BeginUpdate and EndUpdate is devexpress functions that prohibbit browser render control while adding new items. Without this function it takes eternity to finish adding new items.
I know start point of problem it is - item creating code SomeList.AddItem(...).
So my question: is there way to do something like console.trace(SomeList.AddItem(...)) and see full trace which will be executed on first code pass?
Also is there way to determine which function call take alot of time to execute?
In my website I'm Showing my database after user has given the database name, Is there any way I can constantly update the web shown databasebase without refreshing the page . I've tried using setInterval but it's not working for some reason .
function c(){
setInterval(beta, 1000);
}
function beta(){
var d = document.getElementById("opopo").value;
var firebaseRefff= firebase.database().ref('LOCATION/'+d);
firebaseRefff.on('child_added', snap=> {
var slot=snap.getKey();
var alloted=snap.child("ALLOTED").val();
var date=snap.child("DATE").val();
var limit=snap.child("LIMIT").val();
var time=snap.child("TIME").val();
$("table tbody").append(""+slot+""+alloted+""+date+""+limit+""+time+"Null");
});
}
You do not need, and should not use, setInterval to trigger the queries. What you have in your beta() function looks pretty good.
firebaseRefff.on('child_added', snap => {}) means "whenever a child is added under this location, trigger the callback function (empty in my example) with the parameter 'snap'". It will also be called once, initially, for each child that is already at that database reference location.
You need to make sure you've called beta() once to setup this trigger.
If you're still having problems, you might want to insert logging to make sure beta() is being called, what the full reference path is, if the callback is ever triggered, and if your jquery string is correct.
Just the background:
(not really related to the question)
I am using SharePoint and creating a Sharepoint Hosted App.
I have some fields which provide a peoplepicker with which I can select Users out of a user pool. The functioninality is provide by the SharePoint internal scripts.
If I input a name of a user via jquery nothing happens. It has no built-in change handler I guess.
What I have done is a separat script which just resolve the user names on my jquery input via trigger("change") and then the SharePoint internal Scripts doing the job. This "job" is asynchronous and then if the data arrives from the backend the SharePoint Scripts apply the data to the Peoplepicker fields.
But this functions also doesn't support jQuery's trigger because I cannot alter the functions as they're pre-defined...
So want I want to do is to monitor when the text inside the Peoplepicker fields has been changed but I am a little bit lost now.
Question:
I have tried it with the following code (which doesn't work):
$('.peoplePickerDiv').bind("DOMSubtreeModified", function () {
alert("HAS BEEN CHANGED!");
});
Is there another way to react on lets say background editing of input fields in my DOM?
For People Picker control manipulation SPClientPeoplePicker object (clientpeoplepicker.js) is intended, which provides methods for getting information from the picker or to perform other operation.
SPClientPeoplePicker class exposes the following events:
OnControlValidateClientScript - triggers after a server error is set or cleared
OnUserResolvedClientScript - triggers once the resolved user is added or removed in client
OnValueChangedClientScript - triggers after text input or users change in client
OnValueChangedClientScript event probably suits your scenario, here is an example on how to attach it:
var picker = SPClientPeoplePicker.SPClientPeoplePickerDict[peoplePickerId];
picker.OnValueChangedClientScript = function (elementId, userInfo) {
if(userInfo.length > 0){ // once the value is resolved it could be retrieved via `userInfo` object
console.log(userInfo[0]);
}
console.log('value changed');
};
References
Use the client-side People Picker control in SharePoint-hosted SharePoint Add-ins
I'm using Oracle APEX 4.2. I built a PLSQL process that is set to execute "On Demand - When this process is called by AJAX". This process is designed to update two member attributes in a collection that I created when the page loaded. Its code follows:
DECLARE
v_seq_id NUMBER;
BEGIN
--get sequence id
SELECT seq_id into v_seq_id FROM apex_collections
WHERE collection_name = 'THE_COLLECTION' and c001 = :APP_SESSION;
--I've tried uncommenting this script to see if this works, too
--htp.script('alert(''PLSQL Process works'');');
--update first member attribute
apex_collection.update_member_attribute(
p_collection_name =>'THE_COLLECTION',
p_seq => v_seq_id,
p_attr_number => 2,
p_attr_value => 0);
--update second member attribute
apex_collection.update_member_attribute(
p_collection_name =>'THE_COLLECTION',
p_seq => v_seq_id,
p_attr_number => 3,
p_attr_value => sysdate);
END;
When I try calling this process with AJAX/javascript before the page unloads, nothing happens. I placed this code in the "Execute on Page Load" portion of my page:
window.onbeforeunload = function(){
//this alert box works, so I know the function is called
alert('Unloading...');
//call the PLSQL process
var get = new htmldb_Get(null,$v('pFlowId'), 'APPLICATION_PROCESS=THE_PROCESS',1234);
get.get();
//this also works, so I know the function completes
alert('end');
};
I test this two ways. First, I have some logic built into my page that depends on whether or not these member attributes were updated. When I reload the page, it behaves as if the PLSQL process never ran. Second, I have tried uncommenting the htp.script line in the PLSQL code above, but it will not execute either.
When I try running the following in my browser's F12 tools, the console prints "alert('test');" without actually displaying an error message:
var get = new htmldb_Get(null,$v('pFlowId'), 'APPLICATION_PROCESS=THE_PROCESS',1234);
get.get();
I've also tried running it with window.onload, but that doesn't seem to work either.
When I run the PLSQL process as an "After Header" process, the htp.script code launches an alert box successfully, and the process seems to work.
Does anyone know how to get this to work with AJAX? Am I missing something obvious?
It looks like the problem was in the PLSQL process, after all. Following the suggestion from Tom's comment, I looked at wwv_flow.show in the network tab of my browser's development tools. When I viewed the "Response body" tab under "detailed view", I found that the process was returning the results of the htp.script command; it just wasn't generating the alert box itself.
After a bit of troubleshooting, I figured out that the following code in my PLSQL process was not working:
--update first member attribute
apex_collection.update_member_attribute(
p_collection_name =>'THE_COLLECTION',
p_seq => v_seq_id,
p_attr_number => 2,
p_attr_value => 0);
I changed it to :
UPDATE apex_collections SET n001 = 0 WHERE c001 = :APP_SESSION and collection_name = 'THE_COLLECTION';
In order to make this work, I had to execute a command to grant the update permission to my database user:
GRANT UPDATE ON apex_collections TO USER
In a Google Spreadsheet, I have a long script that permorms many actions in steps, like:
function MyLongScript()
{
var Results1 = Action1();
//send feedback 1
var Results2 = Action2(Results1);
//send feedback 2
var Results3 = Action3(Results2);
//send feedback 3
//end code
}
And I want to show the users a dialog box that tells them that script is running and updates each step of the scritp, like "Action1 complete", ..., "Action2 complete" and so on.
So, I have the HTML interface which contains some table rows with these steps. The question is: how do I make the dialog see that the code performed a certain step?
Right now I'm trying to start the code from the dialog after it loads:
$(function() {
google.script.run
.withSuccessHandler(MainCodeSuccess)
.withFailureHandler(MainCodeFailure)
.MyLongScript();
}
And the dialog is called with the UI and HtmlService:
function CallDialog()
{
var ui = HtmlService.createTemplateFromFile('FeedbackWindow')
.evaluate()
.setWidth(300)
.setHeight(500);
SpreadsheetApp.getUi().showModalDialog(ui, "Dialog Title");
}
What I need is either a getStatus() in the dialog scritp or a sendStatus() in the server script.
What is the best way of achieving this?
You can run multiple google.script.run calls to the server simultaneously. You can't have one server call send multiple success calls back. You could have your MyLongScript() run, save progress status somewhere, and just keep that running, then have a second google.script.run executing on a loop every certain time period. You can use a JavaScript setInterval(): window.setInterval("javascript function", milliseconds); I don't think that there is a jQuery equivalent.
So it might (roughly) look like this:
$(function() {
google.script.run
.withSuccessHandler(MainCodeSuccess)
.withFailureHandler(MainCodeFailure)
.MyLongScript();
window.setInterval("statusChecker()", milliseconds);
}
window.statusChecker = function() {
google.script.run
.withSuccessHandler(statusCheckSuccess)
.withFailureHandler(onFailure)
.StatuChecker();
};
window.statusCheckSuccess = function(returnStatus) {
if (returnStatus !== false) {
//To Do - show msg to user
document.getElementById('idMsgToUser').textContent = returnStatus;
};
};
Your MyLongScript() might need to be saving the state of the current status to a file. I'm not sure if the subsequent, and simultaneous google.script.run calls wipes out the data in a global variable. If a global variable would hold the data even with all the simultaneous server scripts running, you could save the current status to a global variable. You'd need to experiment with that, or maybe someone knows the answer to that question.