"Edit Mode" button

Ok, we are making some progress. I installed 2.43 an d the snippet started to work (bingo!!). Now, when I add it to my page that has multiple field editors, it only toggles the first editor on the page and does not toggle others. Looking at the code, it seems that is supposed to iterate and toggle all field editors it finds on the page. Do I need to add some kind of loop, or change syntax somewhere to get all the editors to toggle?

Yep, you’re exactly right. See the updated code below. Also, you don’t need the $(function() {}); bit either, because it’s already wrapped in a snippet that’s being called by a button. I must have been thinking about trying to call it on the initial page load. The big change is the addition of the $.each() loops, and swapping the point where you grab the field editors’ js info.

var $ = skuid.$; // check for "global" toggle state variable // if it doesn't exist, create it if(!window.blEditorMode) window.blEditorMode = 'read'; // this will grab any visible field editor var fieldeditors = $('.nx-basicfieldeditor'); if(window.blEditorMode == 'read') { // toggle button text / icon $('.ui-button:visible').has('.ui-silk-pencil').each(function() { $(this).find('.ui-button-text').text('Switch to Read Mode'); $(this).find('.ui-icon').removeClass('ui-silk-pencil') .addClass('ui-silk-book-open'); }); // find all field editors and switch their mode fieldeditors.each(function(){ // get field editor's js component var fieldeditor = $(this).data('object'); fieldeditor.mode = 'edit' fieldeditor.list.render({doNotCache:true}); }); window.blEditorMode = 'edit'; } else { // toggle button text / icon $('.ui-button:visible').has('.ui-silk-book-open').each(function() { $(this).find('.ui-button-text').text('Switch to Edit Mode'); $(this).find('.ui-icon').removeClass('ui-silk-book-open') .addClass('ui-silk-pencil'); }); fieldeditors.each(function(){ // get field editor's js component var fieldeditor = $(this).data('object'); fieldeditor.mode = 'read' fieldeditor.list.render({doNotCache:true}); }); window.blEditorMode = 'read'; } 

Awesome, this worked!! John, thanks for sticking with this. One (hopefully) last bonus round question. This is lower priority, but would be nice to get working as well. I added the selector for tables as well like shown below. It looks that it is finding the table elements and changes the mode, but the table itself does not change on the page. I suspect the problem might be with this line, that renders the component after mode is changed:

table.list.render({doNotCache:true}); 

Am I close? Perhaps, table renders differently than field editor?

var $ = skuid.$; // check for "global" toggle state variable // if it doesn't exist, create it if(!window.blEditorMode) window.blEditorMode = 'read'; // this will grab any visible field editor var fieldeditors = $('.nx-basicfieldeditor:visible'); //and this wil grab visible tables var tables = $('.nx-skootable:visible'); if(window.blEditorMode == 'read') { // toggle button text / icon $('.ui-button:visible').has('.ui-silk-pencil').each(function() { $(this).find('.ui-button-text').text('Switch to Read Mode'); $(this).find('.ui-icon').removeClass('ui-silk-pencil') .addClass('ui-silk-book-open'); }); // find all field editors and switch their mode fieldeditors.each(function(){ // get field editor's js component var fieldeditor = $(this).data('object'); fieldeditor.mode = 'edit' fieldeditor.list.render({doNotCache:true}); }); // find all tables and switch their mode as well tables.each(function(){ // get field tables' js component var table = $(this).data('object'); console.log('table: ' + table); console.log('table.mode: ' + table.mode); table.mode = 'edit' console.log('table.mode: ' + table.mode); table.list.render({doNotCache:true}); }); window.blEditorMode = 'edit'; } else { // toggle button text / icon $('.ui-button:visible').has('.ui-silk-book-open').each(function() { $(this).find('.ui-button-text').text('Switch to Edit Mode'); $(this).find('.ui-icon').removeClass('ui-silk-book-open') .addClass('ui-silk-pencil'); }); fieldeditors.each(function(){ // get field editor's js component var fieldeditor = $(this).data('object'); fieldeditor.mode = 'read' fieldeditor.list.render({doNotCache:true}); tables.each(function(){ // get field tables' js component var table = $(this).data('object'); console.log('table: ' + table); console.log('table.mode: ' + table.mode); table.mode = 'read' console.log('table.mode: ' + table.mode); table.list.render({doNotCache:true}); }); }); window.blEditorMode = 'read'; } 

Right on. Glad that worked. And a couple things: One, you probably want to move the first closing “});” (the end of your fieldeditors loop) up above your tables loop in the else branch. Otherwise… well, you know. Second, with the table, the list apparently has a mode. If you set…

table.list.mode = 'edit';

then run the list’s render method, it will work.

awesome. this worked and looks like I am all set. Thanks for noticing the incorrect closing bracket :slight_smile: P.S. Might be good to document those components methods as part of your API…

Yep, totally agree. That’s one of our priorities for the near future. Exactly how near future remains to be seen at this point, but I’m hopeful. :slight_smile:

Great work John! AndreyVol - I hope your Skuid work is moving forward well. We’d love to see how things are going with your project.

Rob, I am definitely taking you up on this offer. Will email you offline.

Nothing like coming late to a party! I’ve boiled down the code and suggestions from above and made a few changes to make this a bit easier for an inexperienced user to edit:

// This snippet is designed to be used as a Page Title button. It is, however,<br>// easily adaptable for use in other contexts.<br><br>// Rather than hardcoding the button labels, we recommend you use labels to<br>// support internationalization.<br><br>// ****************************************<br>// Change these variables:<br>var&nbsp;<br>&nbsp; &nbsp; // The primary (default) mode<br>&nbsp; &nbsp; PrimaryMode &nbsp; &nbsp; &nbsp; &nbsp; = 'readonly', // Alternatively: 'read'<br>&nbsp; &nbsp; PrimaryModeLabel &nbsp; &nbsp;= 'Edit My Info',<br>&nbsp; &nbsp; PrimaryModeIcon &nbsp; &nbsp; = 'ui-silk-pencil',<br>&nbsp; &nbsp;&nbsp;<br>&nbsp; &nbsp; // The secondary mode<br>&nbsp; &nbsp; SecondaryMode &nbsp; &nbsp; &nbsp; = 'edit',<br>&nbsp; &nbsp; SecondaryModeLabel &nbsp;= 'All Done',<br>&nbsp; &nbsp; SecondaryModeIcon &nbsp; = 'ui-silk-book',<br>&nbsp; &nbsp;&nbsp;<br>&nbsp; &nbsp; // Set the selector for which components to toggle. For example, to toggle<br>&nbsp; &nbsp; // specific named components, set the selector to:<br>&nbsp; &nbsp; // &nbsp; #ComponentUniqueID1, #AnotherComponent, #AThirdComponent<br>&nbsp; &nbsp; // Or, to toggle all field editors and tables, use this selector:<br>&nbsp; &nbsp; // &nbsp; .nx-basicfieldeditor:visible, .nx-skootable<br>&nbsp; &nbsp; ComponentSelector &nbsp; = '.nx-basicfieldeditor:visible, .nx-skootable';<br>// ****************************************<br><br>var $ = skuid.$,<br>&nbsp; &nbsp; button = arguments[0].button,<br>&nbsp; &nbsp; modes = [ PrimaryMode, SecondaryMode ],<br>&nbsp; &nbsp; currentEditMode = window.pageEditMode || modes[0],<br>&nbsp; &nbsp; newEditMode = ( currentEditMode == modes[0] ) ? modes[1] : modes[0];<br><br>var buttonLabels = {};<br>buttonLabels[modes[0]] = PrimaryModeLabel;<br>buttonLabels[modes[1]] = SecondaryModeLabel;<br><br>var buttonIcons = {};<br>buttonIcons[modes[0]] = PrimaryModeIcon;<br>buttonIcons[modes[1]] = SecondaryModeIcon;<br>&nbsp; &nbsp;&nbsp;<br>// Iterate over the selected components and switch them to the new mode, then<br>// force a re-render.<br>var componentElems = $( ComponentSelector );<br>$.each( componentElems, function( index, componentElem ){<br>&nbsp; &nbsp; var component = $( componentElem ).data( 'component' );<br><br>&nbsp; &nbsp; // Currently, this snippet only supports toggling tables and field editors<br>&nbsp; &nbsp; // However, it would be relatively easy to add other types of components<br>&nbsp; &nbsp; // as appropriate by adding a "case" statement below:<br>&nbsp; &nbsp; switch ( component.type ){<br>&nbsp; &nbsp; &nbsp; &nbsp; case 'skootable':<br>&nbsp; &nbsp; &nbsp; &nbsp; case 'basicfieldeditor':<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var componentObject = $( componentElem ).data( 'object' );<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; componentObject.mode = componentObject.list.mode = newEditMode;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; componentObject.list.render({doNotCache:true});<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; // case 'othertype':<br>&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp; &nbsp;...<br>&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp; &nbsp;break;<br>&nbsp; &nbsp; }<br>});<br><br>// Update the button icon and text to reflect the current mode.<br>button.find('.ui-button-text')<br>&nbsp; &nbsp; .text( buttonLabels[ newEditMode ] );<br>button.find('.ui-icon')<br>&nbsp; &nbsp; .removeClass( buttonIcons[ currentEditMode ] )<br>&nbsp; &nbsp; .addClass( buttonIcons[ newEditMode ] );<br>&nbsp; &nbsp;&nbsp;<br>window.pageEditMode = newEditMode;

As of the Superbank release, this code no longer works.  The component.type field has been renamed to component._componentType.  The fix is simply to change the switch statement from:

switch ( component.type ){


to

switch ( component._componentType ){


Enjoy!

- Chris

This toggle edit button is great, and thanks Chris for the recent update for Superbank release.

I’m wondering if it’s possible for this button to also save the model(s) (assuming the user has made changes to the page).

Right now the user clicks ‘All Done’ which toggles fields back to ‘read’ mode, but they still need to hit ‘Save’ to save the changes. Is it possible for the button to detect if changes have been made on the page, and if so, execute a .save method? 

Chris - We ran in to this as well with the SB release.  We took the approach of using the new “getType” method rather than coding directly to the variable _componentType.  If Skuid decides to change the variable name in the future, it’s less likely the getType method would ever change.

So, instead of:

component._componentType

we have:

component.getType()

Hi Greg -

Using the action framework with a button marked as “Run multiple actions” you can configure the button to save changes (using one or more models of your choice) and then run snippet which flips the mode back to “read” mode.  Underneath, skuid only “saves” things that have changed so if nothing has changed, nothing will be “saved.”

One thing to note if you go this route is to take advantage of the “On Error” action for the “Save” action so that the screen doesn’t flip to read-mode if the “save” fails for some reason.

Hope this helps!

Thanks Barry thats great, I’ll give it a go tonight

Here is another version of the snippet that we use that has an Edit button, and when you click it, it changes to a Save and a Cancel button (and back again when done).  It also does the appropriate model save/cancel and page update accordingly.  We find this model to be a bit more consistent with how other pages in Skuid operates.  It still doesn’t worry about enabling / disabling Save base on if anything has actually changed (which could be added), but it’s pretty close to the native Skuid UI design.

It also changes from using the “window.xxx” context for tracking state to using CSS classes on the buttons - otherwise using this in a Page Include has challenges.

To use it, place two buttons on the page - one called “Edit” (with a CSS class of btnEdit) and another called “Cancel” (with a CSS classes of btnEditCancel and btnHide).  In the resources, I have a CSS rule for  btnHide that simply does “.btnHide { display: none};” so the Cancel button remains hidden when the page loads.

EDIT: Updated to use Barry’s better approach to getting the type using getType()

// Set the selector for which components to toggle. For example, to toggle// specific named components, set the selector to:<br>// &nbsp; #ComponentUniqueID1, #AnotherComponent, #AThirdComponent<br>// Or, to toggle all field editors and tables, use this selector:<br>// &nbsp; .nx-basicfieldeditor:visible, .nx-skootable<br>var ComponentSelector &nbsp; = '.nx-basicfieldeditor:visible, .nx-skootable';<br>var $ = skuid.$;<br><br>// determine what mode was are moving into<br>var button = arguments[0].button;<br>var startEdit = false;<br>var isEditButton = false;<br>if (button.hasClass('btnEdit')) {<br>&nbsp; &nbsp; startEdit = !button.hasClass('btnEditActive');<br>&nbsp; &nbsp; isEditButton = true;<br>} else if (button.hasClass('btnEditCancel')) {<br>&nbsp; &nbsp; startEdit = false;<br>} else {<br>&nbsp; &nbsp; console.log('Unknown button in editModeController; missing class btnEdit or btnEditCancel');<br>&nbsp; &nbsp; return;<br>}<br>// Iterate over the selected components and switch them to the new mode, then<br>// force a re-render.<br>var componentElems = $( ComponentSelector );<br>$.each( componentElems, function( index, componentElem ){<br>&nbsp; &nbsp; console.log('Processing component');<br>&nbsp; &nbsp; console.log(componentElem);<br>&nbsp; &nbsp; var component = $( componentElem ).data( 'component' );<br>&nbsp; &nbsp; console.log(component);<br>&nbsp; &nbsp;&nbsp;<br>&nbsp; &nbsp; // Currently, this snippet only supports toggling tables and field editors<br>&nbsp; &nbsp; // However, it would be relatively easy to add other types of components<br>&nbsp; &nbsp; // as appropriate by adding a "case" statement below:<br>&nbsp; &nbsp; switch ( component.getType() ){<br>&nbsp; &nbsp; &nbsp; &nbsp; case 'skootable':<br>&nbsp; &nbsp; &nbsp; &nbsp; case 'basicfieldeditor':<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var componentObject = $( componentElem ).data( 'object' );<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(componentObject);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; componentObject.mode = componentObject.list.mode = (startEdit ? 'edit' : 'readonly');<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; componentObject.list.render({doNotCache:true});<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br>&nbsp; &nbsp; }<br>});<br>// update buttons and model based on what happened<br>if (startEdit) {<br>&nbsp; &nbsp; // track that we have entered edit mode<br>&nbsp; &nbsp; $('.btnEdit').addClass('btnEditActive');<br>&nbsp; &nbsp; // unhide cancel<br>&nbsp; &nbsp; $('#btnCancelEdit').removeClass('btnHide');<br>&nbsp; &nbsp; // adjust edit to correct text and icon<br>&nbsp; &nbsp; $('.btnEdit').find('.ui-button-text').text('Save');<br>&nbsp; &nbsp; $('.btnEdit').find('.ui-icon').removeClass('sk-icon-page-edit').addClass('sk-icon-save');<br>}<br>else {<br>&nbsp; &nbsp; // track that we have left edit mode<br>&nbsp; &nbsp; $('.btnEdit').removeClass('btnEditActive');<br>&nbsp; &nbsp; // hide cancel button<br>&nbsp; &nbsp; $('#btnCancelEdit').addClass('btnHide');<br>&nbsp; &nbsp; // adjust edit to correct text and icon<br>&nbsp; &nbsp; $('.btnEdit').find('.ui-button-text').text('Edit');<br>&nbsp; &nbsp; $('.btnEdit').find('.ui-icon').removeClass('sk-icon-save').addClass('sk-icon-page-edit');<br>&nbsp; &nbsp; // note that normally you would update the model that is associated with this button, with this line:<br>&nbsp; &nbsp; // var myModel = arguments[0].model;<br>&nbsp; &nbsp; // however, in this case, our model is coming from a page include, so we need more<br>&nbsp; &nbsp; // direct reference to the model<br>&nbsp; &nbsp; var myModel = skuid.model.getModel('LeadDetails');<br>&nbsp; &nbsp; if (isEditButton) {<br>&nbsp; &nbsp; &nbsp; &nbsp; myModel.save({callback: function(result){<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (result.totalsuccess) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; myModel.updateData();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }});<br>&nbsp; &nbsp; } else&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; myModel.cancel();<br>}

Much better!  Thanks - I’ll update my code right now.

Hello and tyvm for this code & explanations, I need to implement this in multiple Tabs

But I’m having some little issues with it

But maybe I just need some clarifications

I created both Buttons Edit & cancel and put css class names you mentioned

Now you only mentioned the resource body for “btnHide”, “.btnHide { display: none};” (IF I Leave Semi-colon at the end it throws me an error, not sure if that is normal)

But what about the resource body for “btnEdit” ?

The problem I’m having is as follow:

When i press Edit button, All the fields go in edit mode, as expected , and the Edit button, now became a save button

1)No cancel field is showing up , if make changes on any field…

Am i missing anything?

Thx

@ chris or anyone that can help,

I still have same issue and cannot figure out the css I would need

In case anyone knows, let me clarify my problem

Chris said:

"To use it, place two buttons on the page - one called “Edit” (with a CSS class of btnEdit) and another called “Cancel” (with a CSS classes of btnEditCancel and btnHide).  In the resources, I have a CSS rule for  btnHide that simply does “.btnHide { display: none};” "

3 different CSS class are mentioned, but the details only provided for 1 of them

 btnHide: “.btnHide { display: none};”

Would anyone know what CSS i would need for those other 2 mentioned?
btnEditCance
btnEdit

Thank you




Dave - those classes (btnEdit and btnCancel) are only needed to identify the buttons. No CSS is needed for it to function, though you are welcome to put some style CSS on them if you want to make your buttons have some style.  Only btnHide needs actual CSS (to hide them).  The code uses btnEdit/btnCancel to understand the button that was clicked, and to flip btnHide between them (so you see either Edit or Cancel, but not both). 

Hope this helps…

Ok thank you very much Chris,

But I must be doing something wrong then.

When i click the edit button, it does change all fields to edit mode(on the tab I’m on only), but the cancel button does not appear no matter what I do,

The snippet (named EditAll)is the exact copy from here so that is not the issue. the only thing possible then is my buttons. So here’s a short description of how i have them set up

1- Edit button: Action type Run Skuid Snippet named EditAll . That button has a class named: btnEdit

2- Cancel button, i tried making it run skuid snippet EditAll, I tried a cancel action, tried no action …
With classes: btnEditCancel btnHide (never used multiple classes, so separated by a space?)

button 1 works fine to edit and save

button 2 never appears


Thx in Advance