Sunday, 9 June 2019

Getting EditTexts Values From RecyclerView

I am building app which user is required fill some data in order to post something, so a fragment consists of edit texts ,radio buttons and spinner along with recyclerview which dynamically renders a number of child layout containing TextView and editText. So when user select category from spinner, some properties which are related to that category are displayed in RecyclerView and user can optionally fill some of them. I have tried to implement this functionality using callback and TextWatcher but I don't get the values I want.

CallBack

interface PropertiesCallback {
    fun addProp(position: Int, title: String, value: String)
}

Adapter

class PropertiesAdapter(private val propertiesCallback: PropertiesCallback)
    : RecyclerView.Adapter<PropertiesAdapter.ViewHolder>() {

    private var list = listOf<CategoriesAndSubcategoriesQuery.Property>()

    fun setData(listOfProps: List<CategoriesAndSubcategoriesQuery.Property>) {
        this.list = listOfProps
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.z_property_input, parent, false)
        return ViewHolder(view)
    }

    override fun getItemCount(): Int = list.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(list[position], position)
    }

    inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
        private val label: TextView = view.findViewById(R.id.label)
        private val input: EditText = view.findViewById(R.id.input)

        fun bind(prop: CategoriesAndSubcategoriesQuery.Property, position: Int) {
            label.text = prop.title()

            prop.hint()?.let { input.hint = prop.hint() }

            input.addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(s: Editable?) {}

                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                    propertiesCallback.addProp(position, prop.title(), input.text.toString())
                }
            })
        }
    }
}

In Fragment

private var propertiesList = mutableListOf<CategoriesAndSubcategoriesQuery.Property>()
private var propertiesInputList = mutableListOf<ProductPropertiesInput>()



  private fun setUpSubcategorySpinner() {
        subcategoriesAdapter = ArrayAdapter(
                this@AddProductFragment.context!!,
                android.R.layout.simple_spinner_item,
                subcategoriesList
        )
        //Subcategories
        subcategoriesAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line)

        subcategory_spinner.adapter = subcategoriesAdapter

        subcategory_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
                subcategoryId = subcategoriesList[position].id()

                //Adding properties
                subcategoriesList[position].properties()?.let {
                    //Clear previous properties data of another subcategory.
                    propertiesInputList.clear()
                    propertiesList.clear()

                    propertiesList.addAll(it)
                    propertiesAdapter.setData(propertiesList)
                    propertiesAdapter.notifyDataSetChanged()
                }
            }

            override fun onNothingSelected(parent: AdapterView<*>) {}
        }
    }

overide

 override fun addProp(position: Int, title: String, value: String) {
        val prop = ProductPropertiesInput
                .builder()
                .title(title)
                .value(value)
                .build()

        propertiesInputList.add(prop)

        //Log.d(TAG, "prop: ${prop.title()} : ${prop.value()}")
    }

submit fun

    private fun submitProduct() {
        //Initializing properties.
        val properties: Any

        //The keys needed in final list.
        val propertyKeys = propertiesList.map { it.title() }

        //Removing objects which keys are not needed.
        propertiesInputList.removeAll { it.title() !in propertyKeys }

        Log.d(TAG, "propertiesInputList: $propertiesInputList")

        //Removing duplicate and assign result in properties var.
        properties = propertiesInputList
                .distinctBy { it.title() }

        Log.d(TAG, "properties: $properties")

        for (prop in properties) {
        Log.d(TAG, "properties , title: ${prop.title()}, value: ${prop.value()} ")
    }
}

Above codes is intended to work as. When user types a value in one of the editText in recyclerView the value will be taken to fragment and added to an object which takes title and value and then added to propertiesInputList.

Problem 1: propertiesInputList will have so many duplicates objects with the same title and I thought best soulution was using distinctBy.

Problem 2: When user fill a number of edittexts which related to lets say category1 and changes his mind and select another category from spinner. The previous values which not part of new chosen category remain in propertiesInputList list. So I thought best solution was to clear propertiesInputList and using removeAll with the titles related to category to filter unwanted objects.

But now I get only the first letter user types. If user types shoes I get s. So it seems distinctBy returns the first object but I want to get exactly last word user typed and If user typed and erased everything i want blank.

Is there a better solution to handle this? Like looping recyclerView only when user press submit instead of textwatcher? Or which part should I fix to make this work?



from Getting EditTexts Values From RecyclerView

No comments:

Post a Comment