Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmatic PDF form filling - iOS #106

Merged
merged 3 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,32 @@ class PSPDFKitView extends React.Component {
NativeModules.PSPDFKitViewManager.addAnnotations(annotations, findNodeHandle(this.refs.pdfView));
}
}

/**
* Gets the value of the form element of the fully qualified name.
*
* @param fullyQualifiedName The fully qualified name of the form element.
*
* Returns a promise resolving a dictionary with the following structure:
* {'value' : value} or ['error' : Failed to get the form field value.]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

['error' : Failed to get the form field value.] is still shown as an array literal, while it should be an object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Fixed in e709bf1

*
* @platform ios
*/
getFormFieldValue = function (fullyQualifiedName) {
return NativeModules.PSPDFKitViewManager.getFormFieldValue(fullyQualifiedName, findNodeHandle(this.refs.pdfView));
}

/**
* Set the value of the form element of the fully qualified name.
*
* @param value The string value form element. For button form elements pass 'selected' or 'deselected'. For choice form elements, pass the index of the choice to select, for example '1'.
* @param fullyQualifiedName The fully qualified name of the form element.
*
* @platform ios
*/
setFormFieldValue = function (value, fullyQualifiedName) {
NativeModules.PSPDFKitViewManager.setFormFieldValue(value, fullyQualifiedName, findNodeHandle(this.refs.pdfView));
}
}

PSPDFKitView.propTypes = {
Expand Down
7 changes: 7 additions & 0 deletions ios/RCTPSPDFKit/RCTPSPDFKitView.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,17 @@
@property (nonatomic, copy) RCTBubblingEventBlock onAnnotationsChanged;
@property (nonatomic, copy) RCTBubblingEventBlock onStateChanged;

/// Document
- (void)saveCurrentDocument;

/// Anotations
- (NSDictionary<NSString *, NSArray<NSDictionary *> *> *)getAnnotations:(PSPDFPageIndex)pageIndex type:(PSPDFAnnotationType)type;
- (void)addAnnotation:(NSString *)jsonAnnotation;
- (NSDictionary<NSString *, NSArray<NSDictionary *> *> *)getAllUnsavedAnnotations;
- (void)addAnnotations:(NSString *)jsonAnnotations;

/// Forms
- (NSDictionary<NSString *, NSString *> *)getFormFieldValue:(NSString *)fullyQualifiedName;
- (void)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName;

@end
49 changes: 48 additions & 1 deletion ios/RCTPSPDFKit/RCTPSPDFKitView.m
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ - (void)addAnnotations:(NSString *)jsonAnnotations {
PSPDFDataContainerProvider *dataContainerProvider = [[PSPDFDataContainerProvider alloc] initWithData:data];
PSPDFDocument *document = self.pdfController.document;
PSPDFDocumentProvider *documentProvider = document.documentProviders.firstObject;

BOOL success = [document applyInstantJSONFromDataProvider:dataContainerProvider toDocumentProvider:documentProvider error:NULL];
if (success){
[self.pdfController reloadData];
Expand All @@ -198,6 +197,54 @@ - (void)addAnnotations:(NSString *)jsonAnnotations {
}
}

#pragma mark - Forms

- (NSDictionary<NSString *, id> *)getFormFieldValue:(NSString *)fullyQualifiedName {
if (fullyQualifiedName.length == 0) {
NSLog(@"Invalid fully qualified name.");
return nil;
}

PSPDFDocument *document = self.pdfController.document;
for (PSPDFFormElement *formElement in document.formParser.forms) {
if ([formElement.fullyQualifiedFieldName isEqualToString:fullyQualifiedName]) {
id formFieldValue = formElement.value;
return @{@"value": formFieldValue ?: [NSNull new]};
}
}

return @{@"error": @"Failed to get the form field value."};
}

- (void)setFormFieldValue:(NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName {
if (fullyQualifiedName.length == 0) {
NSLog(@"Invalid fully qualified name.");
return;
}

PSPDFDocument *document = self.pdfController.document;
for (PSPDFFormElement *formElement in document.formParser.forms) {
if ([formElement.fullyQualifiedFieldName isEqualToString:fullyQualifiedName]) {
if ([formElement isKindOfClass:PSPDFButtonFormElement.class]) {
if ([value isEqualToString:@"selected"]) {
[(PSPDFButtonFormElement *)formElement select];
} else if ([value isEqualToString:@"deselected"]) {
[(PSPDFButtonFormElement *)formElement deselect];
}
} else if ([formElement isKindOfClass:PSPDFChoiceFormElement.class]) {
((PSPDFChoiceFormElement *)formElement).selectedIndices = [NSIndexSet indexSetWithIndex:value.integerValue];
} else if ([formElement isKindOfClass:PSPDFTextFieldFormElement.class]) {
formElement.contents = value;
} else if ([formElement isKindOfClass:PSPDFSignatureFormElement.class]) {
NSLog(@"Signature form elements are not supported.");
} else {
NSLog(@"Unsupported form element.");
}
break;
}
}
}

#pragma mark - Notifications

- (void)annotationChangedNotification:(NSNotification *)notification {
Expand Down
23 changes: 21 additions & 2 deletions ios/RCTPSPDFKit/RCTPSPDFKitViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ @implementation RCTPSPDFKitViewManager
if (annotations) {
resolve(annotations);
} else {
reject(@"error", @"Failed to get annotations", nil);
reject(@"error", @"Failed to get annotations.", nil);
}
});
}
Expand All @@ -109,7 +109,7 @@ @implementation RCTPSPDFKitViewManager
if (annotations) {
resolve(annotations);
} else {
reject(@"error", @"Failed to get annotations", nil);
reject(@"error", @"Failed to get annotations.", nil);
}
});
}
Expand All @@ -121,6 +121,25 @@ @implementation RCTPSPDFKitViewManager
});
}

RCT_EXPORT_METHOD(getFormFieldValue:(NSString *)fullyQualifiedName reactTag:(nonnull NSNumber *)reactTag resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
dispatch_async(dispatch_get_main_queue(), ^{
RCTPSPDFKitView *component = (RCTPSPDFKitView *)[self.bridge.uiManager viewForReactTag:reactTag];
NSDictionary *formElementDictionary = [component getFormFieldValue:fullyQualifiedName];
if (formElementDictionary) {
resolve(formElementDictionary);
} else {
reject(@"error", @"Failed to get form field value.", nil);
}
});
}

RCT_EXPORT_METHOD(setFormFieldValue:(nullable NSString *)value fullyQualifiedName:(NSString *)fullyQualifiedName reactTag:(nonnull NSNumber *)reactTag) {
dispatch_async(dispatch_get_main_queue(), ^{
RCTPSPDFKitView *component = (RCTPSPDFKitView *)[self.bridge.uiManager viewForReactTag:reactTag];
[component setFormFieldValue:value fullyQualifiedName:fullyQualifiedName];
});
}

- (UIView *)view {
return [[RCTPSPDFKitView alloc] init];
}
Expand Down
56 changes: 56 additions & 0 deletions samples/Catalog/Catalog.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,17 @@ var examples = [
component.props.navigator.push(nextRoute)
},
},
{
name: 'Programmatic Form Filling',
description:
'Shows how to get the value of a form element and how to programmatically fill forms.',
action: component => {
const nextRoute = {
component: ProgrammaticFormFilling
}
component.props.navigator.push(nextRoute)
},
},
{
name: 'Debug Log',
description: 'Action used for printing stuff during development and debugging.',
Expand Down Expand Up @@ -459,6 +470,51 @@ class ProgrammaticAnnotations extends Component {
}
}

class ProgrammaticFormFilling extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<PSPDFKitView
ref="pdfView"
document={'PDFs/Form_example.pdf'}
disableAutomaticSaving={true}
configuration={{
backgroundColor: processColor('lightgrey'),
thumbnailBarMode: 'scrollable',
}}
style={{ flex: 1, color: pspdfkitColor }}
/>
<View style={{ flexDirection: 'row', height: 60, alignItems: 'center', padding: 10 }}>
<View>
<Button onPress={() => {
// Fill Text Form Fields.
this.refs.pdfView.setFormFieldValue('Appleseed', 'Name_Last');
this.refs.pdfView.setFormFieldValue('John', 'Name_First');
this.refs.pdfView.setFormFieldValue('1 Infinite Loop', 'Address_1');
this.refs.pdfView.setFormFieldValue('Cupertino', 'City');
this.refs.pdfView.setFormFieldValue('CA', 'STATE');
this.refs.pdfView.setFormFieldValue('123456789', 'SSN');
this.refs.pdfView.setFormFieldValue('(123) 456-7890', 'Telephone_Home');
this.refs.pdfView.setFormFieldValue('1/1/1983', 'Birthdate');

// Select a button form elements.
this.refs.pdfView.setFormFieldValue('selected', 'Sex.0');
this.refs.pdfView.setFormFieldValue('selected', 'PHD');
}} title="Fill Forms" />
</View>
<View>
<Button onPress={ async () => {
// Get the First Name Value.
const firstNameValue = await this.refs.pdfView.getFormFieldValue('Name_Last');
alert(JSON.stringify(firstNameValue));
}} title="Get Last Name Value" />
</View>
</View>
</View>
)
}
}

export default class Catalog extends Component {
render() {
return (
Expand Down
Binary file added samples/PDFs/Form_example.pdf
Binary file not shown.