Проблема внедрения зависимости Петрушки в Flex 4 с использованием шаблона Presentation Model
У меня есть класс View EmployeeList следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<s:NavigatorContent xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:parsley="http://www.spicefactory.org/parsley"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
<fx:Script>
<![CDATA[
import cafeparsley.model.EmployeeListPM;
[Inject]
[Bindable]
public var model : EmployeeListPM;
[Init]
public function init () : void {
model.init();
}
]]>
</fx:Script>
<s:Panel title="Employee List" horizontalCenter="0">
<s:HGroup paddingTop="50">
<s:Button label="Add New Employee" click="model.addNewEmployee()" />
<mx:Spacer width="100%" />
<s:Button label="Logout" click="model.logout()" />
<mx:Spacer width="100%" height="20" />
</s:HGroup>
<s:List id="empList" dataProvider="{ model.employees }" labelFunction="model.properName"
change="model.initUpdateEmployee(empList.selectedItem);empList.selectedIndex = -1;" width="100%" />
<s:Label id="error" color="0xFF0000" />
</s:Panel>
</s:NavigatorContent>
ПМ выглядит так:
package cafeparsley.model
{
import cafeparsley.events.EmployeeEvent;
import cafeparsley.events.NavigationEvent;
import cafeparsley.services.impl.EmployeeServiceImpl;
import cafeparsley.vo.Employee;
import flash.events.EventDispatcher;
import mx.collections.ArrayCollection;
import mx.rpc.IResponder;
[Bindable]
[Event(name="navigationEvent", type="cafeparsley.events.NavigationEvent")]
[ManagedEvents("navigationEvent")]
public class EmployeeListPM extends EventDispatcher implements IResponder
{
public var employeeService : EmployeeServiceImpl = new EmployeeServiceImpl();
public var employees : ArrayCollection;
public function init() : void
{
loadEmployees();
}
public function EmployeeListPM()
{
}
public function loadEmployees():void
{
employeeService.loadEmployees( this );
}
Независимо от того, использую ли я или autowiring для выполнения впрыска, при запуске этого я получаю следующее сообщение об ошибке:
Ошибка типа: ошибка № 1009: невозможно получить доступ к свойству или методу пустой ссылки на объект. в cafeparsley.view::EmployeeList/_EmployeeList_List1_i()[C:\dev\code\workspace\ examples\CafeParsley\src\cafeparsley\view\EmployeeList.mxml:29] в cafeparsley.view::EmployeeList/_EmployeeList_Array2xc(at).core::DeferredInstanceFromFunction/getInstance()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\DeferredInstanceFromFunction.as:105] в spark.components::SkinnableContainer/createDeferredContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:985] на spark.components::SkinnableContainer/createContentIfNeeded()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:1014] по адресу spark.components::SkinnableContainer/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer. как:827] в mx.core::UIComponent/initialize()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7349] в mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7241] на mx.core::UIComponent/addChildAt()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:6947] на spark.components::Group/addDisplayObjectToDisplayList()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:1825] на spark.components:: группы / HTTP://www.adobe.com/2006/flex/mx/internal::elementAdded()[E:\ DEV \ 4.x \ каркасов \ проекты \ искру \ SRC \ искра \ компонента \ Group. как:1416] в spark.components::Group/setMXMLContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:512] в spark.components::Group/set mxmlContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:452] на spark.components::SkinnableContainer/set mxmlContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:604] на spark.components::SkinnableContainer/createDeferredContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:986] на сайте spark.component s:: SkinnableContainer / createContentIfNeeded () [E: \ dev \ 4.x \ frameworks \ projects \ spark \ src \ spark \ components \ SkinnableContainer.as: 1014] на spark.components::SkinnableContainer/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:827] по адресу spark.components::NavigatorContent/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\NavigatorContent.as:225] в mx.core::UIComponent/initialize()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7349] at cafeparsley.view::EmployeeList/initialize()
Таким образом, employeeListPM имеет значение null при возникновении ошибки. Однако, если я закомментирую<s:List>
компонент, перезапустите и установите точку останова в методе init, будет вызываться init(). Так что дело не в том, что моя контекстная конфигурация неверна, просто в том, что ПМ не был введен вовремя и выдается ошибка. Но в соответствии с руководством Parsley, если я использую автопроводку или <parsley:configure/>
PM должен быть введен к тому времени, когда это необходимо.
Я не вижу, что я делаю неправильно, в том, что я считал относительно простым сценарием внедрения зависимости. Вы можете помочь?
2 ответа
Пара моментов здесь:
Ваш пример не включает <Configure />
или же <FastInject />
теги, однако, так как вы упоминаете их в своем посте, я предполагаю, что они просто отсутствуют в примере кода. (Если нет, то вам нужно добавить один из них, чтобы это работало).
Однако, скорее всего, в вашем коде есть условия гонки.
В частности, эти строки:
labelFunction="model.properName"
change="model.initUpdateEmployee(empList.selectedItem);empList.selectedIndex = -1;"
Model
является внедренным свойством, однако не гарантируется, что оно было внедрено во время первого запуска кода.
Вместо этого переместите код в скрипт внутри класса, который выполняет проверку на ноль, а затем откладывает логику обратно в PM.
то есть:
labelFunction="nameFunction"
private function nameFunction(item:Object):String
{
return (model) ? model.properName(item) : "";
}
Следует также учитывать, что вы вызываете model.init() из функции View, помеченной метатегом Parsley [Init]. Я бы посоветовал вам применить тот же метатег [Init] к методу init () модели.
[Init]
public function loadEmployees():void {
employeeService.loadEmployees( this );
}
Делайте это вместо вызова model.init() из представления. В документации Altho the Lifecycle говорится:
Методы, помеченные [Init], вызываются после создания экземпляра объекта и обработки всех инъекций.
У меня были гораздо более согласованные результаты: не вызывать какие-либо методы init () между внедренными объектами напрямую, а использовать подход метаданных с тегами.