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")
}
})