skip to Main Content

Let’s say I have a data class Dog that includes a List of puppies.

@immutable
class Dog extends Equatable{
    final int id;
    final List<Puppy> listOfPuppies;

    Dog({required this.id,required  this.listOfPuppies});


    Dog copyWith({int? newId, List<Puppy>? newListOfPuppies}){
        return Dog(id: newId ?? id, listOfPuppies: newListOfPuppies ?? listOfPuppies);
}

  @override
  List<Object?> get props => [id, listOfPuppies];
}

@immutable
class Puppy extends Equatable{
  final String name;
  final int age;

  Puppy({required this.name, required this.age});
  
  Puppy copyWith({int? newAge, String? newName}){
        return Puppy(age: newAge?? age, name: newName ?? name);
  }
    
  @override
  List<Object?> get props => [name, age];
}

And later down the line I need to update one of the puppies inside the dog class without:

  1. Changing the order of the listOfPuppies variable provided using Riverpod (important)
  2. Affecting the other puppies and possibly re-creating them unnecessarily (not important)

For reference I’m using Riverpod and providing the dog anywhere in the app. This is the controller class:

class DogController extends StateNotifier<Dog>{
  DogController(super.state);
  
  void updatePuppy(Puppy newPuppy){
    //update specific puppy here inside the listOfPuppies list
    //state = state.copyWith(listOfPuppies: );
  }
}

I’m clueless on how I need to update the puppy using the constraints given above.

2

Answers


  1. Chosen as BEST ANSWER

    My case was a bit more tedious, but with the given instructions from Ruble I was able to update everything smoothly. In my case there was only one more model that was including the Dog class.

    Owner model:

    class Owner extends Equatable {
      final List<Dog> dogs;
      
      const Owner({required this.dogs});
    
      Owner copyWith(List<Dog>? newDogs){
        return Owner(dogs: newDogs?? dogs);
      }
      ...
    }
    

    Dog model:

    class Dog extends Equatable {
      final List<Puppy> puppies;
      
      const Dog({required this.puppies});
    
      Dog copyWith(List<Puppy>? newPuppies){
        return Dog(puppies: newPuppies?? puppies);
      }
      ...
    }
    

    And finally the Puppy model was as following:

    class Puppy extends Equatable {
      final bool isVaccinated;
    
      const Puppy({required this.isVaccinated});
    
      Puppy copyWith(bool? newIsVaccinated){
        return Puppy(isEnabled: newIsVaccinated?? isVaccinated);
      }
      ...
    }
    

    To update the isVaccinated field inside one of the Puppy models I had to follow these steps inside the controller class:

    void updatePuppy(Puppy puppyToUpdate, bool newIsVaccinated){
      //1. find the Dog index that contains the Puppy passed as parameter
      final dogIndex = state.owner.dogs!.indexWhere((dog) => dog.puppies!.contains(puppyToUpdate));
      //2. save all old dogs so we can update them later
      final listOfOldDogs = state.owner.dogs!;
      //3. save the dog that contains the puppy we need (with the index we found in step 1)
      final selectedDog = state.owner.dogs![dogIndex];
      //4. save all old puppies so we can update them later
      final listOfOldPuppies = selectedDog.puppies!;
      //find the puppy index that is equal to the puppy passed as parameter
      final puppyIndex = selectedDog.puppies!.indexWhere((puppy) => puppy == puppyToUpdate);
      //update relevant puppy inside the old puppy list (saved in step 4)
      listOfOldPuppies[puppyIndex] = puppyToUpdate.copyWith(isVaccinated: newIsVaccinated);
      //create a section same as the one we selected above in [selectedSection] variable, by just updating its list of fields
      final updatedDog = selectedDog.copyWith(puppies: listOfOldPuppies);
      //update the selected dog in the listOfOldDogs list (saved in step 2)
      listOfOldDogs[dogIndex] = updatedDog;
      //copy the whole list of dogs into the owner using its copyWith method
      final newOwner = state.owner.copyWith(dogs: listOfOldDogs);
      //finally update the state with the new owner
      state = state.copyWith(owner: owner);
    }
    

    This way old puppies and dogs were not moved inside the list and only the relevant puppy's isVaccinated field was updated.


  2. You can do it this way:

    void updatePuppy(Puppy newPuppy){
        
        final oldListOfPuppies = state.listOfPuppies;
        final indexNewPuppy = state.listOfPuppies.indexOf(newPuppy);
        
        oldListOfPuppies[indexNewPuppy] = newPuppy;
        
        state = state.copyWith(
        newListOfPuppies: oldListOfPuppies
        );
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search