# VGSCollect and States

### VGSCollect

An object you use for observing `VGSTextField` states and send data

#### Declaration

```swift
class VGSCollect
```

#### Creating a VGSCollect

```swift

/// Initialzation.
///
/// - Parameters:
///   - id: your organization vault id.
///   - environment: your organization vault environment with data region.(e.g. "live", "live-eu1", "sanbox").
///   - hostname: Custom Hostname, if not set, data will be sent to Vault Url
init(id: String, environment: String, hostname: String? = nil)

/// Initialzation.
///
/// - Parameters:
///   - id: your organization vault id.
///   - environment: your organization vault environment. By default `Environment.sandbox`.
///   - dataRegion: id of data storage region (e.g. "eu-123").
///   - hostname: Custom Hostname, if not set, data will be sent to Vault Url
init(id: String, environment: Environment = .sandbox, dataRegion: String? = nil, hostname: String? = nil)
```

> • All **VGSCollect** instances in the app will be working independently and only with fields that have them in `VGSConfiguration` settings.\
> • All **VGSCollect** instances can be configured differently.

`VGSCollect` instance grab the data from `VGSTextFields` during `sendData(_:)` request. By default, it has strong reference with all textfield and files related with to it. If you need to remove reference from textfield or file before `VGSCollect` instance is deallocated, you can do it manually whenever you need it.

#### Code example

```swift

/// unsubscribe single VGSTextField
vgsCollect.unsubscribeTextField(cardNumber)

/// unsubscribe all VGSTextFields related to VGSCollect instance
vgsCollect.unsubscribeAllTextFields()

```

#### Multiple Data Regions

Please use the following configuration to set up a specific data region if needed.

```swift
/// Check your data region, it should look like: "live-eu-1"
/// In your code follow the VGSCollect initialization pattern
var vgsCollect = VGSCollect(id: "<VAULT_ID>", environment: .live, dataRegion: "eu-1")

///When you set enivronment as String, you can point region directly in environment string
var vgsCollect = VGSCollect(id: "<VAULT_ID>", environment: "live-eu-1")
```

#### Add a Custom Hostname

When integrated with VGS, by default, the traffic is passed via VGS proxy, which has `tntxxxxx.sandbox.verygoodproxy.com` format, where `tntxxxxx` is your Vault identifier. Collect SDK allows you to use your custom hostname and make requests to a non-VGS domain name or localhost (on your local machine).\
Before adding a new Hostname you should create a CNAME record for your existing domain in your DNS provider’s account that should point to `<VAULT_ID>.<ENVIRONMENT>.verygoodproxy.com`.

\*\* Learn more about [Custom Hostnames](/vault/http-proxy/inbound-connection/custom-hostnames.md)\*\*.

Then, in your Application create a `VGSCollect` instance with the Custom Hostname:

```swift

var vgsCollect = VGSCollect(id: "<VAULT_ID>", environment: <ENVIRONMENT>, hostname: "www.customdomain.com")

```

> • When the hostname is not valid or not registered in VGS system, it will be ignored by SDK and all the traffic will be passed via VGS proxy directly.\
> • Only **https** scheme is supported.\\

## Observing States

There are three types of `VGSTextField` states available that depends on choosen `FieldType` in `VGSConfiguration`: **State**, **VGSCardState** and **VGSSSNState**.

### State

An object you use for observing `VGSTextField` parameters that depends on input and `VGSConfiguration`.

#### Declaration

```swift
class State
```

You should not create **State** object by itself. Instead, get access to it from `VGSTextField.state` attribute. `State` object and it's attributes are **read-only**.

#### Some of State attributes

| **Attribute** | **Type/Default value**                                      |
| ------------- | ----------------------------------------------------------- |
| `fieldName`   | `VGSConfiguration.fieldName` associated with `VGSTextField` |
| `isValid`     | Contains `VGSTextField` current validation state            |
| `inputLength` | Contains user input characters count in `VGSTextField`      |

To get a full list of `State` attributes check [VGSCollectSDK Reference docs](https://verygoodsecurity.github.io/vgs-collect-ios/Classes/State.html)

### VGSCardState

An object you use for observing `VGSTextField` parameters when `VGSConfiguration.type` defined as `FieldType.cardNumber`.

#### Declaration

```swift
class VGSCardState: State
```

**VGSCardState** extends default `State` with more specific attributes related to credit card numbers

#### VGSCardState attributes

| **Attribute** | **Type/Default value**                                            |
| ------------- | ----------------------------------------------------------------- |
| `last4`       | Last 4 digits of the valid card number                            |
| `bin`         | Bin digits of the valid card number                               |
| `cardBrand`   | `CardType` object describing Credit Card Brand of the card number |

> * **bin** and **last4** attributes will be empty until the input card number is valid.

To get a full list of supported card brands check [VGSCollectSDK Reference docs](/vault/developer-tools/vgs-collect/test-data.md#test-credit-and-debit-cards)

### VGSSSNState

An object you use for observing `VGSTextField` parameters when `VGSConfiguration.type` defined as `FieldType.ssn`.

#### Declaration

```swift
class VGSSSNState: State
```

**VGSSSNState** extends default `State` with more specific attributes related to social security numbers

#### VGSSSNState attributes

| **Attribute** | **Type/Default value**                 |
| ------------- | -------------------------------------- |
| `last4`       | Last 4 digits of the valid card number |

> * **last4** attributes will be empty until the input social security number is valid.

#### Code example

```swift
extension ViewController: VGSTextFieldDelegate {
  /// Check
  func vgsTextFieldDidChange(_ textField: VGSTextField) {

    /// VGSCardState is extended State for textfields with type .cardNumber
    if let cardState = textField.state as? VGSCardState {
      if cardState.cardBrand.cardLengths.contains(cardState.inputLength) {
        print("User add full card number")
      }
      if cardState.isValid {
        print("\(cardState.cardBrand.stringValue): \(cardState.bin)******\(cardState.last4)")
      }
    }

    /// VGSSSNState is extended State for textfields with type .ssn
    else if let ssnState = textField.state as? VGSSSNState {
      if ssnState.isValid {
        print("\(ssnState.last4)")
      }
    }
  }
}
```

### State Publisher

If you preffere to use Combine framework, you can observe state changes with `.statePublisher` attribure. It will be triggered on each `VGSTextField`'s interaction event, similar to `VGSTextFieldDelegate` events.

#### Declaration

```swift
/// `VGSTextFieldStatePublisher` publisher that emits the `State` of a given `VGSTextField`.
var statePublisher: VGSTextFieldStatePublisher
```

#### Code example

```swift
/// Track textfield state changes
cardHolderName.statePublisher.sink { [weak self] state in
  self?.cardHolderName.borderColor = state.isValid ? .lightGray : .red
}.store(in: &cancellables)

/// Map State to VGSCardState to get access for card attributes
cardNumber.statePublisher.compactMap { state -> VGSCardState? in
  return state as? VGSCardState
}.sink { [weak self] cardState in
  self?.cardNumber.borderColor = cardState.isValid ? .lightGray : .red
}.store(in: &cancellables)
```

### Observe VGSTextField states

You can observe states every time `VGSTextField` input is changed. Observer callback will be called on each `VGSTextField`'s interaction event. For more granular editing events handler, check [VGSTextFieldDelegate](/vault/developer-tools/vgs-collect/ios-sdk/ui-components.md#vgstextfielddelegate) methods.

```swift
/// Observe only focused text field
var observeFieldState: ((_ textField: VGSTextField) -> Void)?

/// Observe all text fields registered in a VGSCollect instance
var observeStates: ((_ form: [VGSTextField]) -> Void)?
```

#### Code example

```swift
// ...

/// Observe all textfields states on editing
vgsCollect.observeStates = { textFields in

    textFields.forEach({ textField in
         print(textField.state.description)

         /// VGSCardState is extended state for textfields with type .cardNumber
         if let cardState = textField.state as? VGSCardState, cardState.isValid {
              print("\(cardState.cardBrand.stringValue): \(cardState.bin)******\(cardState.last4)")
         }
    })
}
```

For more details about available attributes and functionality check [VGSCollectSDK Reference docs](https://verygoodsecurity.github.io/vgs-collect-ios/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/ios-sdk/state.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
