Karatte
Karatte

Reputation: 25

AngularJS - bind ng-model with button click

I've got an irritating problem with data binding using ng-model and button.

The principle of operation of my site:

  1. My HTML site displays a list of projects (loaded from external .json file).
  2. Each row has a button named Edit which displays a modal containing some <input type="text" filled with relevant data about project (like project.name, project.date etc.)
  3. Initial value of input is equal to object data (text-input called Name will contain project.name etc.)
  4. Object is modified only if you click Save button and confirm the operation (confirm(sometext) is okay). Closing the modal, not clicking the button or pressing cancel on confirmation box should prevent data from being updated.
  5. Editing input (let's say that project.name is "Project2" and I modify it by adding 3 numbers resulting in "Project2137"), closing modal and opening it again should result in "Project2" text inside input (because object wasn't modified, only input)

So far I understand that single text input should look like this

<input type="text" id="editName" class="form-control" ng-model = "project.name">

Using ng-model means that they are binded. That's what I know. However editing input means that object is updated as soon as I enter some data. I tried to fiddle with ng-model-options but I didn't find any possible solutions.

I tried to do it programmatically as well using

<input type="text" id="editName" class="form-control" value = {{project.name}}>
....
<button type="button" class="btn pull-right btn-primary btn-md" ng-click="edit(project)" data-dismiss="modal" >Save</button>

And function:

$rootScope.edit = function(project)
    {
        if(confirm("Are you sure to save changes?"))
            {
                 project.name = angular.element(document.getElementById('editName')).val();
             //  ...and so on with other properties

This solution is kinda close to what I wanted to achieve (object is updated only on confirm), but I faced another problem: input loads data from object only once at the beginning instead of each time the modal is opened which is against rule #5

Is there any way to fix this using either ng-model bind or custom function? Or maybe there is some other, easier way?

--EDIT--

Here I don't have any problem with saving the data using a button, everything works well and clicking Save is reflected in a projects list. (well until I hit a F5 key). The problem is that input text is not properly binded to project and that's what I want to fix.

  1. Sample data (pseudocode)

    project1.name = "Proj1" project2.name = "Proj2"

  2. I click an Edit button on row #1

  3. Text input displays "Proj1". Everything is fine.
  4. I change input by adding some random characters like "Proj1pezxde1"
  5. Text input is now "Proj1pezxde1"
  6. I do not click Save button.
  7. I close the modal.
  8. Project summary still displays "Proj1". Okay.
  9. I click an edit button on first row

10. Text input is "Proj1pezxde1" even though I didn't modify an object.

Text input should read data from object again (each time I open this modal) and thus display "Proj1"

That's the problem I want to fix. Sorry for being a little bit inaccurate.

Upvotes: 1

Views: 2688

Answers (4)

Deep
Deep

Reputation: 9794

You can create a copy of the project object in modal controller and use this object to bind with the input element of the modal

$scope.copyProj = angular.copy($scope.project);

Assign the copy object properties to project only when save is clicked.

Upvotes: 1

Supradeep
Supradeep

Reputation: 3266

So , as I understand from your question , you need to update the project data only if it is saved. To do that you can maintain a copy of the actual object which get updated only it is saved like below :

Here we are using angular.copy(), which does a deep copy of the source object.

$scope.original = {name : "xyz"};
$scope.project = angular.copy(original);

//Call this when the user confirms to save , here we are replacing the 
//original copy with the latest object that needs to be saved.

$scope.save = function () {
  $scope.original = angular.copy($scope.project);
}

//Call this when closing the modal or clicking cancel or when losing     
//focus, this will reset the changes to the original copy.

$scope.reset = function () {
  $scope.project = angular.copy(original);
}

Upvotes: 0

Ron Dadon
Ron Dadon

Reputation: 2706

The simplest way to do this in my opinion is using a second object that is a copy of the project, and after confirmation applying the changes to the original project object.

For example, a simple "pseudo code" of a controller:

function MyCtrl($scope) {
    $scope.projects = [...];
    $scope.currentProject = null;

    $scope.edit = function(project) {
        $scope.currentProject = angular.copy(project); // This will create a copy so the changes in $scope.currentProject will not reflect.
        // Open dialog with input bound to $scope.currentProject
        if (confirm) {
            // Assign all properties from currentProject to project
            angular.extend(project, $scope.currentProject);
        }
    }
}

Upvotes: 0

UBK
UBK

Reputation: 242

As per my understanding after reading the provided descriptions, you have a list of projects, which is being used as in an repeater and you want to bind each projects data to a Text box and a Button.

Have you tried initializing your Projects object following way?

$scope.projects = [
        { 'name': 'proj1', 'id': '1' },
        { 'name': 'proj2', 'id': '2' }
    ];

Then you can do something like below to show your data

<div ng-repeat="project in projects">
    <div>
       <input type="text" class="form-control" ng-model = "project.name">
       <button type="button" class="btn pull-right btn-primary btn-md" ng-click="edit(project)" data-dismiss="modal" >Save</button>
    </div>
</div>

Upvotes: 0

Related Questions