UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: How to display the value accordingly to the list selected.

Forums > 100 Days of SwiftUI

I want to display a detailed view when they click on the list itme like in the mission view back in moonshot project. but the data is stored by the user in the animeitem struct. the problem is when i click the list item in content view it is displaying all the data stored or added using the animeView sheet. What to do if i want to display the specific sheet details only in AnimeDetails View? Content View:

import SwiftUI

struct ContentView: View {
    @ObservedObject var anime = Anime()
    @State private var showingAnime  = false
    var body: some View {
        NavigationView {

            List {
                NavigationLink(destination: AnimeDetails(anime: anime)) {
                ForEach(anime.items) {
                    items in

                    HStack {
                        VStack(alignment: .leading) {
                            Text(items.name)
                                .font(.headline)

                            Text(items.watchStatus)

                        }
                        Spacer()

                        Text("Times watched: \(items.timesWatched)")

                    }
                }

                .onDelete(perform: removingRows)
                }

            }
            .navigationBarTitle("Anime Tracker")
            .navigationBarItems(leading: EditButton(), trailing:
                                    Button(action: {
                                        self.showingAnime = true
                                    }) {
                                        Image(systemName: "plus")
                                    })
            .sheet(isPresented: $showingAnime) {
                AnimeView(anime: self.anime)
            }

        }
    }
    func removingRows(at offsets: IndexSet) {
        anime.items.remove(atOffsets: offsets)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Anime Details:

import SwiftUI

struct AnimeDetails: View {
    @ObservedObject var anime: Anime
    @State private var timeswatched = 0

    var body: some View {
        ForEach(anime.items, id: \.id) {
            item in
            VStack (alignment: .leading) {
                Text("Genre: \(item.genre)")

                Text("\(item.watchStatus)")

                    Text("Review: \(item.review)")

                Spacer()
            }
        .navigationBarTitle("\(item.name)")
        }

    }
}

AnimeItem struct:

import Foundation

struct AnimeItem: Codable, Identifiable {
    var id =  UUID()
    let name: String
    let genre: String
    let timesWatched: Int
    let review: String
    let watchStatus: String
}

class Anime: ObservableObject {
    @Published var items = [AnimeItem]() {
        didSet {
            let encoder = JSONEncoder()

            if let encoded = try?
                encoder.encode(items) {
                UserDefaults.standard.set(encoded, forKey: "Item")
            }
        }
    }

    init() {
        if let items = UserDefaults.standard.data(forKey: "Item") {
            let decoder = JSONDecoder()

            if let decoded = try?
                decoder.decode([AnimeItem].self, from: items) {
                self.items = decoded
                return
            }
        }
        self.items = []
    }

}

AnimeView:

import SwiftUI

struct AnimeView: View {
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var anime: Anime
    @State private var name = ""
    @State private var genre = ""
    @State private var review = ""
    @State private var timesWatched = 0
    @State private var watchStatus = ""
    @State private var writingReview = false
    var watchStatusList = ["Watching", "Planning", "Watched", "Not sure"]
    var genreList = ["Action", "Adventure", "Harem", "Ecchi", "Romance", "Shounen"]
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Enter the Anime Name")) {
                    TextField("Enter Name", text: $name)
                    }
                Section(header: Text("Select the genre of the anime")) {
                    Picker("Select the Genre", selection: $genre) {
                        ForEach(self.genreList, id: \.self){
                            Text($0)
                        }
                    }
                }
                Section(header: Text("Watch Status")) {
                    Picker("Have you watched it?", selection: $watchStatus) {
                        ForEach(self.watchStatusList, id: \.self) {
                            Text($0)
                        }
                    }
                }
                if watchStatus == "Watched" {
                    Section(header: Text("Times Watched")) {
                        VStack {
                        Stepper("Choose the times watched", value: $timesWatched)
                            Text("Times you have watched - \(timesWatched)")
                        }
                    }
                }
                Button("Do you want to write a review?") {
                    self.writingReview = true
                }

                if writingReview {
                    Section(header: Text("Write your review")) {
                        TextField("Review", text: $review)
                    }
                }
            }
            .navigationBarTitle("Anime Information")
            .navigationBarItems(trailing: Button("Save") {
                let item = AnimeItem(name: name, genre: genre, timesWatched: timesWatched, review: review, watchStatus: watchStatus)
                self.anime.items.append(item)
                self.presentationMode.wrappedValue.dismiss()
            })
        }
    }
}

2      

Because 1) you have your ForEach wrapped within the NavigationLink, and 2) the AnimeDetails view takes the entire Anime observed object and loops through its items again. What you need to do is something like this:

List {
    ForEach(anime.items) { item in
        NavigationLink(destination: AnimeDetails(anime: item)) {

            HStack {
                VStack(alignment: .leading) {
                    Text(item.name)
                        .font(.headline)

                    Text(item.watchStatus)

                }
                Spacer()

                Text("Times watched: \(item.timesWatched)")

            }
        }
    }
    .onDelete(perform: removingRows)
}

And AnimeDetails should take a single AnimeItem instead of the entire Anime observed object.

2      

Thank you

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.