@@ -793,66 +793,78 @@ class DataHarmonizer {
793
793
794
794
/* Currently only called via Footer.js
795
795
* numRows is (usually) user specified number of rows to add at bottom
796
- * of current dh table. However, if table has foreign key to another
797
- * table, the other table's focused row controls foreign key entries
796
+ * of current dh table. However, if table has foreign key(s) to another
797
+ * table, the other table's focused row will control foreign key values
798
798
* added to this table.
799
799
*/
800
800
addRowsToBottom ( numRows ) {
801
+
802
+ numRows = parseInt ( numRows ) ; // Coming from form string input.
801
803
// Get the starting row index where the new rows will be added
802
804
const startRowIndex = this . hot . countRows ( ) ;
803
-
804
- if ( ! this . context . oneToManyAppContext ) {
805
+
806
+ // If this has no foreign key parent table(s) then go ahead and add x rows.
807
+ if ( ! this . context . relations ?. [ this . template_name ] ?. parent ) {
805
808
// Insert the new rows below the last existing row
806
809
this . hot . alter ( 'insert_row_below' , startRowIndex , numRows ) ;
807
810
return ;
808
811
}
809
812
810
- // Validate and process the current selection
811
- const is1mAndHasParent = ( class_assignment ) => {
812
- const unique_keys =
813
- this . context . oneToManyAppContext . appContext [ class_assignment ]
814
- . unique_keys ;
815
- for ( let key in unique_keys ) {
816
- if ( 'foreign_key' in unique_keys [ key ] ) {
817
- return unique_keys [ key ] . foreign_key ;
818
- }
813
+ // Here we deal with adding rows that need foreign keys.
814
+ // Locate each foreign key and fetch its focused value, and copy into new
815
+ // records below.
816
+ // If missing key value(s), prompt user to focus appropriate tab(s) row
817
+ // and try again.
818
+
819
+ let required_selections = { } ;
820
+ let selection_error = '' ;
821
+ Object . entries ( this . context . relations ?. [ this . template_name ] ?. parent )
822
+ . forEach ( ( [ parent_name , parent ] ) => {
823
+ Object . entries ( parent )
824
+ . forEach ( ( [ slot_name , foreign_slot_name ] ) => {
825
+ // Determine if foreign key field has been selected
826
+ let hot_parent = this . context . dhs [ parent_name ] . hot ;
827
+ let slot_value ;
828
+ // getSelected() returns array with each row being a selection range
829
+ // e.g. [[startRow, startCol, endRow, endCol],...].
830
+ let selected = hot_parent . getSelected ( ) ;
831
+ if ( selected ) {
832
+ let hot_col = this . getColumnIndexByFieldName ( slot_name ) ;
833
+ // Get first selection's first row.
834
+ slot_value = hot_parent . getDataAtCell ( selected [ 0 ] [ 0 ] , hot_col ) ;
835
+ if ( ! slot_value || slot_value . length == 0 ) {
836
+ selected = false ;
837
+ }
819
838
}
820
- return false ;
821
- } ;
822
- const classIsForeignKeyForClassAndCurrentSelection = (
823
- maybe_child_class ,
824
- currentSelection
825
- ) => {
826
- const unique_keys =
827
- this . context . oneToManyAppContext . appContext [ maybe_child_class ]
828
- . unique_keys ;
829
- return (
830
- ! isEmptyUnitVal ( unique_keys [ currentSelection . shared_key_name ] ) &&
831
- maybe_child_class !== currentSelection . source
832
- ) ;
833
- } ;
834
- // check if the DH refers to a parent class or class with no children.
835
- // if it has a parent, ensure a foreign key is selected in some parent
836
- // if it doesn't have a parent, use regular add rows implementation
837
- if ( is1mAndHasParent ( this . class_assignment ) ) {
838
- if (
839
- ! isEmptyUnitVal ( this . context . currentSelection ) &&
840
- ! isEmptyUnitVal ( this . context . currentSelection . valueToMatch ) &&
841
- classIsForeignKeyForClassAndCurrentSelection (
842
- this . class_assignment ,
843
- this . context . currentSelection
844
- )
845
- ) {
846
- // Insert the new rows below the last existing row
847
- this . hot . alter ( 'insert_row_below' , startRowIndex , numRows ) ;
848
- // Find the nearest index after the last non-empty row in the specified column
849
- this . populateNewRows ( numRows , startRowIndex ) ;
850
- } else {
851
- console . warn ( 'No current selection to populate the new rows.' ) ;
852
- $ ( '#empty-parent-key-modal' ) . modal ( 'show' ) ;
853
- }
839
+ if ( ! selected ) {
840
+ //required_selections[slot_name] = {source: parent_name};
841
+ selection_error += `<li> <b>${ parent_name } </b> (${ foreign_slot_name } )</li>` ;
842
+ }
843
+ else {
844
+ required_selections [ slot_name ] = slot_value ;
845
+ }
846
+ } ) ;
847
+ } ) ;
848
+
849
+ if ( selection_error ) {
850
+ // Prompt user to select appropriate parent table row(s) first.
851
+ $ ( '#empty-parent-key-modal-info' ) . html ( selection_error ) ;
852
+ $ ( '#empty-parent-key-modal' ) . modal ( 'show' ) ;
853
+ return ;
854
854
}
855
855
856
+ this . hot . alter ( 'insert_row_below' , startRowIndex , numRows ) ;
857
+
858
+ // Populate new rows with selected value(s)
859
+ this . hot . batch ( ( ) => {
860
+ for ( let row = startRowIndex ; row < startRowIndex + numRows ; row ++ ) {
861
+ Object . entries ( required_selections ) . forEach ( ( [ slot_name , value ] ) => {
862
+ const col = this . getColumnIndexByFieldName ( slot_name ) ;
863
+ this . hot . setDataAtCell ( row , col , value ) ;
864
+ } ) ;
865
+ } ;
866
+ } ) ;
867
+
856
868
}
857
869
858
870
getColumnIndexByFieldName ( slot_name ) {
@@ -865,53 +877,7 @@ class DataHarmonizer {
865
877
return - 1 ;
866
878
}
867
879
868
- // Function to populate the new rows with the selected value
869
- populateNewRows ( numRows , baseColCoord ) {
870
- const { shared_key_name, valueToMatch, source } =
871
- this . context . currentSelection ;
872
- const col = this . getColumnIndexByFieldName ( shared_key_name ) ;
873
-
874
- // Retrieve shared keys for the current class assignment, if any
875
- const sharedKeys =
876
- this . context . schema_tree [ this . class_assignment ] ?. shared_keys || [ ] ;
877
-
878
- if ( valueToMatch !== null && sharedKeys . length > 0 && col !== - 1 ) {
879
- sharedKeys . forEach ( ( shared_key_spec ) => {
880
- const { name, relation, related_concept } = shared_key_spec ;
881
-
882
- // Check if the current column matches the shared key and the source matches the related concept
883
- const currentColumnName = this . slots [ col ] . name ;
884
- const isMatchingKey =
885
- currentColumnName === name &&
886
- relation === 'parent' &&
887
- source === related_concept ;
888
-
889
- if ( isMatchingKey ) {
890
- this . hot . batch ( ( ) => {
891
- this . populateCells ( numRows , baseColCoord , col , valueToMatch ) ;
892
- } ) ;
893
- }
894
- } ) ;
895
- }
896
- }
897
-
898
- // Function to populate cells with the selected value, checking for non-empty cells to avoid overwriting
899
- populateCells ( numRows , baseColCoord , col , valueToMatch ) {
900
- for ( let i = 0 ; i < numRows ; i ++ ) {
901
- const targetRowIndex = baseColCoord + i ;
902
-
903
- // Check if the target row is empty before setting the value to avoid overwriting
904
- const existingValue = this . hot . getDataAtCell ( targetRowIndex , col ) ;
905
- if ( existingValue === null || existingValue === '' ) {
906
- this . hot . setDataAtCell ( targetRowIndex , col , valueToMatch ) ;
907
- } else {
908
- console . warn (
909
- `Skipping row index ${ targetRowIndex } as it already contains a value.`
910
- ) ;
911
- }
912
- }
913
- }
914
-
880
+ /*
915
881
// Function to find the nearest index after the last non-empty value
916
882
findNearestIndexAfterLastNonEmpty(column) {
917
883
// Initialize nearestIndex to the first index (0)
@@ -933,6 +899,7 @@ class DataHarmonizer {
933
899
// Return the index immediately after the last non-empty value
934
900
return nearestIndex;
935
901
}
902
+ */
936
903
937
904
/**
938
905
* Hides the columns at the specified indexes within the Handsontable instance.
0 commit comments