How to Remove or Add Record

Thanks Mark. I saw that setting, and don’t know how it got turned off. I fixed that and a couple other things that were wrong. Now this works properly. If you don’t mind, I’d like to ask a few questions to help me make the application more streamlined. Here is my GenerateReports form:


When I click one of the study group names the IsSelected properly flips and updates the form. When I click action buttons for All Groups and No Groups, all X’s and checkmarks properly get set.

Question 1:
Right now, I have 4 client-side functions that get called when I click the various action buttons. Is there any way I can, inside the function called by the click event, identify just which button was clicked? Knowing this would allow me to do everything in a single client-side function. In c#, I’m used to having a “sender” property that returns the object that generated the event.

Question 2:
Ditto for clicking one of the study groups in the subform. You don’t see on the screenshot, but below the study groups there is another similar subform for the Portfolios attached to that report. If I click a StudyGroup Name, I believe I do have access to the underlying StudyGroupKey in the fields collection. Clicking a Portfolio in the other subform should also give me access to the PortfolioKey for the record I clicked. Could I check for the undefined state of each of those keys to identify where I clicked? This would let me economize on how many functions I need to code. Or is there a better way?

Question 3:
Here is a snippet of a typical client-side function. This was suggested by you folks:

    const _five = five;
    five.executeFunction('InitSubformServer', myParms, null, '', '', function (result) {
        if (result.serverResponse.errorCode === 'ErrErrorOk') {
            five.refreshTable(joinTable);
            five.reload();
            return;
        }
        
        let functionMessage = result.serverResponse.results;
        if (functionMessage !== '') {
            _five.showMessage(functionMessage);
        }
    });
    
    return five.success(result);

This is working fine, but I’m curious: why in the first IF block does the code return, and without the five.success(result) that’s on the bottom. Wouldn’t it be better to not return, and put the balance of the function in an else{} block (except for the final return)? If the first IF is true, doesn’t that guarantee that the second IF will be false? And why is there a statement that sets _five to the five object?

Thanks so much for your help so far!

Hello,

singleFunctionMultipleButtons.fdf (3.3 MB)

I have attached an FDF with uses one function to alter the output of multiple buttons (this application has two buttons, one adds and one multiplies). To see the output that comes from each button, run the application using the inspector.

BREAKDOWN:
Note: In my example I have created buttons using processes, however, the same principles apply for all buttons.

I have created to processes to be used as the buttons, take note of the actionID.

I have then created and attached this function (to the OnClick)) to both of the buttons. It essentially works by using an if statement to output the result depending on the actionID of the button that is pressed.

I have put these processes into a dashboard and have attached them to a menu. The above image displays the output of pressing add, then multiply, then add, then add. As you can see, the output changes depending on which button is pressed all from using the one function.

Similar principles should apply for the question 2.

In regard to your third question:
From what I can see within this code snippet, the _five variable is not required, rather you can just refer to five as ‘five.FUNCTION’… meaning instead of _five.showMessage(…) you can use five.showMessage(…).

In regards to the return statement, it tells the program to execute the ‘executeFunction’ block, however, the program still executes the five.success(result) function.

Also, if you would prefer having the two if statements as an if-else block, that is fine to do so, just ensure you conduct testing after making the change to ensure it does not break anything.

Hope this helps,

Thanks,
Riley.

Hi Riley,

Thanks so much for answering my questions. I was under the impression that actionID() referred to the form itself. That’s why I asked how to identify which action button was pressed.

Haven’t yet loaded your FDF, but from the email I think I see what you are doing.

Am I correct in my inference that whatever object generated the event will be the object referred to by actionID()? I didn’t exactly understand this from the documentation. If you reply “yes”, then that will clear things up considerably. If so, it seems like I may need to know the form’s ID AND the button’s ID. I suppose I could load a variable with “current form” whenever I load a form, then use actionID() for the button???

One final question (I know, we all say that, huh?) and I can make a lot of progress.

Currently, I’m working on the GenerateReports form, but the SetupReports form also needs this functionality. The difference being the SetupReports form needs to save the chosen groups in the join table, and the GenerateReports form does not. I would use a Join Page on SetupReports, but there is no easy way to “select all” or “select none” for the detail page. I could run code to update the join table, but I’ve been told by you folks that it won’t visually update the join page unless I leave the form and come back. That is almost useless to me, because changes should be reflected in the UI immediately in my opinion.

So I decided to use the same DataView on both forms. That way, the UI is updated immediately. Now, I just need to update the join table based on what is in the Selected… table once my changes are done (for the SetupReports form only). So how do I do this? I don’t see an event that fires when the form closes, only one that fires when you click the “save” button.

Since the form’s save button is not enabled by updating a page based on a DataView (the way it is when using a Join page), IS THERE A WAY, IN CODE, TO ENABLE THE SAVE BUTTON FOR THE GENERAL FORM PAGE AS IF I HAD CLICKED “EDIT” OR CHANGED A VALUE ON THE GENERAL PAGE?

Thanks…

Ron Mittelman

UPDATE:

I loaded your FDF, and it seems to work fine. However, when I put a log statement in the SetIsSelectedAllGroups and SetIsSelectedNoGroups functions, which say "five.log('actID: ’ + five.actionID());
The log shows “GenerateReports”, which is the name of the form. So I know nothing of processes at this point, but why is yours showing the actionID of the button, but mine is showing the actionID of the form?

This is so confusing. Maybe your code doesn’t work the same for a defined action button rather than a process?

This part is not critical, as I was trying to economize on code and not need a function for every action button. But why can’t I get my application to work like yours does?

I still need the questions from my prior post answered. Thanks for working with me on this.

Hello,

Would you like to send me your application so I can take a look at it.

And in regard to your second message, it may be different depending on where the function has been attached, either way, I can take a look at this is well.

Thanks,
Riley.

Thanks Riley,

As mentioned, the issue is not critical, I just wanted to be able to economize on how many functions I need. One “select all” and one “select none” seems better than 4 different functions to handle all or no groups and all or no portfolios for the subforms. If there is a way to do that, I would be grateful if you could show me.
BrandeisConejo-20240905-153744782903685.fdf (5.6 MB)

Hi Riley,

As mentioned, this line of inquiry is not important at all. I can simply have different client functions for each button rather than having one that works for multiple buttons depending on the name of the button.

I’m having a more fundamental problem that I hope you can advise me on.
My aim is to use the same dataview for the SetupReports and GenerateReports forms. The dataview will enable me to modify the SelectedGroups table, then use that table to actually generate my report. For the SetupReports form, I also want to use any changes in the SelectedReports table to also modify the ReportGroups join table. This should be easy enough to differentiate based on the actionID.

Given this form:


When I click the 3rd button (MOVIE BUFFS), not only do I want to update the SelectedGroups table and the UI, I also want to change the join table. So my idea is to delete all records in the join table FOR THE SELECTED REPORT, then add them back in from the SelectedGroups table. Here is where I’m having problems.

My testing shows that when I include the ReportsKey in my context for calling the server function, it never gets there. I’m properly adding various values to the context object, including the ReportsKey, but when I log the operation, that is missing from the context object. Here is my code to load that object:

    let myParms = {
        Form: myForm,
        SelectedTable: myTable,
        UserKey: five.getVariable('UserKey'),
        SelectedField: 'StudyGroupKey',
        SelectedValue: five.field.StudyGroupKey,
        JoinTable: 'ReportGroups',
        JoinField1: 'ReportKey',
        JoinField2: 'StudyGroupKey',
        JoinValue1: five.field.ReportsKey
        // add IsSelected: true|false if setting all
    };

Is there an issue with using five.field.ReportsKey (which is plainly visible in the General page) from code which is running from the dataview? The entire context variable is empty, even the name of the field. I try logging the context string and it’s not there. I try logging the field itself and it’s not there. Strange, but when I look at the variables in the inspector, that value IS there. Do I need to include a field from the general page into the query and data view for the action page also? That’s the only thing I can think of. Or is there another way for the code which is triggered from the data view click event to be aware of the ReportsKey from the General page? Should I be using the stack instead of five.field???

If you can help with this one question, I can wait on all the other answers. Thanks…

UPDATE: I was able to get this to work by using five.stack.Reports.ReportsKey rather than five.field.ReportsKey. Can you please verify that is the correct fix, and that five.field.some parent form field won’t work by design? Thanks…

Hello,


Using stack is the correct option in this case as the ReportsKey is not present within five.field, this is because there is no field within the data view in which relates to the ReportsKey.

Hope this helps,
Thanks,
Riley.

Thanks for the quick answer Riley.

My code is still not working properly, even though I solved the issue with ReportsKey. Here is the function:

function SetIsSelectedServer(five, context, result)  {
    
    // modify IsSelected for supplied Table depending on context
    // optionally update the join table if Form = 'Setup...'

    /*context = {
        Form: 'GenerateReports',
        SelectedTable: 'SelectedGroups',
        UserKey: five.getVariable('UserKey'),
        SelectedField: 'StudyGroupKey',
        SelectedValue: five.field.StudyGroupKey,
        JoinTable: 'ReportGroups',
        JoinField1: 'ReportKey',
        JoinValue1: five.field.ReportsKey,
        JoinField2: 'StudyGroupKey',
        IsSelected: true|false
    };*/
    
    // if context contains IsSelected, update IsSelected for all records in SelectedTable for supplied UserKey
    // otherwise, flip IsSelected for specific record in SelectedTable for UserKey where SelectedField = SelectedValue

    // if Form is Setup...:
    //  update join table to match SelectedTable records for supplied JoinValue1
    //  ex: for SelectedGroups: join table = ReportGroups, JoinValue1 = ReportsKey, JoinField2 = StudyGroupKey

    five.log('SetIsSelectedServer');
    let sql = '';
    
    // for initial testing, use GenerateReport form rather than SetupReport form
    let isSetup = context.Form.startsWith('Generate');
    // let isSetup = context.Form.startsWith('Setup');

    // if setting IsSelected for all records for supplied UserKey to true|false:
    if (context.IsSelected !== undefined) {
        sql = `UPDATE ${context.SelectedTable} SET \`IsSelected\` = ${context.IsSelected} WHERE UserKey = ?`;
        result = five.executeQuery(sql, 0, context.UserKey);
    }
    
    // if flipping IsSelected for particular record for supplied UserKey and FieldValue:
    else { 
        sql = `UPDATE ${context.SelectedTable} SET \`IsSelected\` = NOT \`IsSelected\` WHERE UserKey = ? AND ${context.SelectedField} = ?`;
        result = five.executeQuery(sql, 0, context.UserKey, context.SelectedValue);
    }
    
    // if changing Setupxxx table, clear and update the join table
    if (isSetup){
        
        sql = `DELETE FROM \`${context.JoinTable}\` WHERE \`${context.JoinField1}\` = ?`;
        five.log(sql);
        five.log(context.JoinValue1);
        result = five.executeQuery(sql, 0, context.JoinValue1)
        
        let sql1 = `INSERT INTO \`${context.JoinTable}\` ( ${context.JoinField1}, ${context.JoinField2} ) `; 
        let sql2 = `SELECT '${context.JoinValue1}' AS \`${context.JoinField1}\`, \`${context.SelectedField}\` FROM \`${context.SelectedTable}\` `;
        // let sql2 = `SELECT '${context.JoinValue1}', \`${context.SelectedField}\` FROM \`${context.SelectedTable}\` `;
        let sql3 = `WHERE \`${context.SelectedTable}\`.\`IsSelected\` = true AND \`${context.SelectedTable}\`.\`UserKey\` = ?`;
        five.log(sql1);
        five.log(sql2);
        five.log(sql3);
        five.log(context.UserKey);
        result = five.executeQuery(sql, 0, context.UserKey)
    }

    return five.success(result);
}

This partially works. The last part doesn’t work.
NOTE: The last part should only be executed if I’m working from the SetupReports form. Since I haven’t yet finished that form, I’m forcing it to execute the final code from the GenerateReports form instead. You can see this in the section of code near the beginning starting with // for initial testing. This part seems to be ok, because my log statements are being executed.

I think the SQL is right, but not positive.

The first part of the function (the part that flips the IsSelected column in SelectedGroups table is working. I run the application and choose the report, then quickly query the database and get the following:

Then I click the first group name and get a check mark in the UI, then query the database and get the following:


So the part that updates the SelectedGroups table seems to work fine.

The last part is supposed to clear the ReportGroups join table of all records for the particular report. I think this works.

Then, the ReportGroups join table is supposed to be loaded with any records in the SelectedGroups table for the current user that have IsSelected = true. This is the part that is not working.

Am I doing something wrong with the last query?

Thanks again…

Oh crap, never mind. I found an SPE (stupid programmer error). Forgot to set the sql variable to sql1+sql2+sql3 before executing the last sql statement. It works now. Only reason I used multiple SQL statements was for logging purposes, because I can’t read long SQL in the inspector.

If you happen to know how to tell the name of the action button that was clicked I’d still like to know that. Your earlier idea may work for processes, but it doesn’t seem to work when it’s a defined action button.

Thanks…