I'm working on a lightning application for managing work items & tasks. Currently, I'm having trouble with just updating just one instance of a workItem component I have. The way I have things now, all my workItems change in my application.
Other questions
- How do I manage changing just one work item instance?
- Is it a good choice to have my modal at the root of my application? Since my modal is at the root & not in the same DOM hierarchy as my workItem components, I can't use a "component" event to handle events up the chain & I feel like this is complicating things.
- When should I be using application events? Any brief example scenarios would be appreciated.
Current Flow:
- User clicks "Add Task" button inside a workItem component, which fires an application 'addTaskEvent' event. - At my application root I have a 'taskModal' component. The 'taskModal' has a handler listening for the application "addTaskEvent" event & when it handles it, it just unhides the modal. When the modal is open, the user can insert a new task name, then click either cancel or save. If save is hit in the modal, I fire another application event, with the new task name packaged. - My workItem component has a handler defined for the application event the modal fired. My handler function for this event simply grabs the new task name that the modal event gave me & I just push & update the tasks for the work Item. - **Problem**: when I push my new task, all of workItems get updated with the new task, instead of just the workItem I initially clicked. I realize this is because all of workItems are listening to the same event the modal triggered. taskboardApp.app
<aura:application extends="force:slds"> <c:AA_taskboard /> ---> workList.cmp --> workItem.cmp <c:AA_taskModal/> </aura:application> taskboard.cmp the taksboard controller simply fetches the work items on init & adds the work items to the workItems attribute.
<aura:component controller="AA_taskboardController"> <aura:attribute name="workItems" type="agf__ADM_Work__c[]" description="all of the items for the current sprint"/> <aura:handler name="init" action="{!c.doInit}" value="{!this}" description="fetches work item data"/> <div class="slds-container--x-large slds-container--center"> <c:AA_workList workItems="{!v.workItems}" /> </div> <c:AA_taskModal /> </aura:component> Worklist.cmp
<aura:component> <aura:attribute name="workItems" type="agf__ADM_Work__c[]" /> <ol class="work-list"> <aura:iteration items="{!v.workItems}" var="workItem"> <li class="work-item-container"> <c:AA_workItem work="{!workItem}" tasks="{!workItem.agf__Tasks__r}"/> </li> </aura:iteration> </ol> </aura:component> WorkItem.cmp
<aura:component> <aura:attribute name="work" type="agf__ADM_Work__c" /> <aura:attribute name="tasks" type="agf__ADM_Task__c[]"/> <aura:attribute name="showTasks" type="Boolean" default="false" /> <aura:registerEvent name="addTaskEvent" type="c:AA_addTaskEvent" description=" an application event fired when user clicks add task button on this work item. Task modal component at the root(taskboard.cmp) listens for this event."/> <aura:handler event="c:AA_updateTaskEvent" action="{!c.updateTask}" description="Handler for application event fired from the task modal after the user had entered a new task name & hit save. This event sends up the taskname to a workItem component that's listening for it"./> <div class="work-item"> <header >{!v.work.agf__Subject__c}</header> <button onclick="{!c.addTask}">Add Task</button> <!-- Tasks --> <ol class="work-tasks"> <aura:iteration items="{!v.work.agf__Tasks__r}" var= "taskItem"> <li class="task-item"> <c:AA_taskItem task="{!taskItem}" /> </li> </aura:iteration> </ol> </div> <div> </aura:component> workItemController.js
({ toggleShowTasks: function(component, event, helper) { component.set("v.showTasks" , !component.get('v.showTasks')); }, addTask: function(component, event, helper){ var appEvent = $A.get("e.c:AA_addTaskEvent"); appEvent.setParams({ work : component.get("v.work") }); appEvent.fire(); console.log('fired addtask event from WORK') }, updateTask: function(component, event, helper){ console.log('fired update task in work item-------------------'); var taskName = event.getParams("taskName").taskName; var newTask = {agf__Subject__c: taskName}; var workTasks = component.get("v.tasks"); console.log("the work item-----", workTasks) workTasks.push(newTask); component.set("v.tasks", workTasks); //all work items get pushed my new task since workItem.cmp //has a listener } }) taskModal.cmp
<aura:component> <div class="task-modal hide" aura:id="task-modal"> <!-- other code removed for brefvity --> <ui:inputText aura:id="task-input" class="slds-input"/> <button onclick="{!c.cancelTask}" >Cancel</button> <button onclick="{!c.saveTask}" >Save</button> </div> </aura:component> taskModalController.js
({ showTaskModal: function(component, event, helper) { var taskModal = component.find('task-modal'); $A.util.removeClass(taskModal, "hide") var workItem = event.getParams('work').work; console.log('event.getParams(work??)', workItem); component.set('v.work', workItem); }, cancelModal: function(component, event, helper){ }, //when our modal opens we attach a work item to the modal, so it should be available here by now. //note: I tried to pass the work component via the addTask event but you can't. There's no type value with component for the attribute you creaate in an event. saveTask: function(component, event, helper){ var taskInput = component.find('task-input'); var taskName = taskInput.get("v.value"); var updateEvent = $A.get("e.c:AA_updateTaskEvent"); updateEvent.setParams({'taskName': taskName}); updateEvent.fire(); var taskModal = component.find('task-modal'); $A.util.addClass(taskModal, "hide") //clear modal text taskInput.set('v.value', "") console.log("FIRED updateTask from saveTask function"); }, cancelNewTask: function(component, event, helper){ var taskModal = component.find('task-modal'); $A.util.addClass(taskModal, "hide") } })