I'm having trouble getting an event listener to work in a mobile app (Built in Flash Builder 4.5, Flex SDK 4.5.1)
I have an event class called BMS_Event.as which looks like this:
package model
{
import flash.events.Event;
public class BMS_Event extends Event
{
public static var COMPLETE_EVENT:String = "BMSData_Complete";
public static var FAULT:String = "BMSDatafault";
public var data:*;
public function BMS_Event(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false)
{
this.data = data;
super(type, bubbles, cancelable);
}
}
}
A class to dispatch the event:
package model
{
import flash.events.Event;
import flash.events.EventDispatcher;
import model.BMS_Event;
public class BMSDataParser extends EventDispatcher
{
public function BMSDataParser()
{
trace("BMSDataParser function");
var BMSDataCompleteEvent:BMS_Event = new BMS_Event(BMS_Event.COMPLETE_EVENT);
dispatchEvent(BMSDataCompleteEvent);
}
}
}
And in my Mobile App view, two functions to call the eventparser, and then an eventlistener which listens for the complete event:
import model.BMSDataParser;
import model.BMS_Event;
protected function getData():void
{
var parser:BMSDataParser = new BMSDataParser();
parser.addEventListener(BMS_Event.COMPLETE_EVENT, bmstest);
}
private function bmstest(e:BMS_Event):void
{
trace("bmstest function");
}
The problem I'm having is that the event listener isn't firing, everything works fine up until that point. It does work in a web application, but for whatever reason not a mobile app.
I'm new to mobile app development - is this a limitation of AIR mobile Apps?
Any help/suggestions greatly appreciated.
Thanks
Maybe make var parser:BMSDataParser a private class variable, and in the creationComplete or initialized events of the class add parser.addEventListener(BMS_Event.COMPLETE_EVENT, bmstest);
One more thing: if your using ViewNavigatorApplication with Views, the views are not created until they are pushed onto the view stack e.g. navigator.pushView(PayNowView);, so any listeners will not be activated unless they are displayed first
Related
With WebVeiw2 you can send a message to a web app running in it using WebView2Ctrl?.CoreWebView2?.PostWebMessageAsJson(message).
Is there a way of doing this in CefSharp
Create a class (I used JavascriptCallbackMessenger) to Set and Run the callbacks.
public class JavascriptCallbackMessenger
{
private IJavascriptCallback _callback;
public void SetCallBack(IJavascriptCallback callback)
{
_callback = callback;
}
public void RunCallback(string message)
{
if (_callback != null && _callback.CanExecute)
{
_callback.ExecuteAsync(message);
}
}
}
Create an instance of JavascriptCallbackMessenger and register it with the CefSharp control
CefSharpCtrl.JavascriptObjectRepository.Register(JavascriptCallbackMessengerName, _messenger, true, BindingOptions.DefaultBinder);
Set the callback in Javascript as follows (I'm not a JS developer, but this was my solution).
(async function() {
const cefSharp = (window as any).CefSharp;
await cefSharp.BindObjectAsync(JavascriptCallbackMessengerName);
window.javascriptCallbackMessenger.setCallBack(function(message: string)
{
console.log("messageHandler: " + message);
})
})();
I was using typescript, so I had to extend the Window with the newly created variable.
declare global {
interface Window { javascriptCallbackMessenger: any; }
}
Apologies, but the formatting seems to be a bit "off"!
trying to setup a multi-tenant site using ABP.io framework 3.1.
I am trying to set the <meta keywords (amongst other tags) in the page html head. I am attempting to get the values from a database field for the current tenant so the meta keywords will be specific for the tenant.
I tried to follow the sample that is available here: https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface#layout-hooks where they inject a google analytics script code into the head tag.
this is fine, as it is static text, but when i try to load the partial page with a model it throws an error of expecting a different model to that which is passed in.
So far i have the Notification View Componet
Public class MetaKeywordViewComponent : AbpViewComponent
{
public async Task<IViewComponentResult> InvokeAsync() {
return View("/Pages/Shared/Components/Head/MetaKeyword.cshtml"); //, meta);
}
}
and the cshtml page
#using MyCompany.MyProduct.Web.Pages.Shared.Components.Head
#model MetaKeywordModel
#if (Model.SiteData.Keywords.Length > 0)
{
<meta content="#Model.SiteData.Keywords" name="keywords" />
}
and the cshtml.cs file as
public class MetaKeywordModel : MyProductPageModel
{
private readonly ITenantSiteDataAppService _tenantSiteDataAppService;
public TenantSiteDataDto SiteData { get; private set; }
public MetaKeywordModel(ITenantSiteDataAppService tenantSiteDataAppService)
{
_tenantSiteDataAppService = tenantSiteDataAppService;
}
public virtual async Task<ActionResult> OnGetAsync()
{
if (CurrentTenant != null)
{
SiteData = await _tenantSiteDataAppService.GetSiteDataAsync();
}
return Page();
}
}
but when i run the program i get the following error.
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook.LayoutHookViewModel', but this ViewDataDictionary instance requires a model item of type 'MyCompany.MyProduct.TenantData.Dtos.TenantSiteDataDto'.
How do i pass the data from my database into the page to be rendered if i can't use my model?
Any help tips or tricks would be greatly appreciated.
Regards
Matty
ViewComponent is different from the razor page.
See https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-3.1#view-components
You should inject the service in view component class directly. like:
public class MetaKeywordViewComponent : AbpViewComponent
{
private readonly ITenantSiteDataAppService _tenantSiteDataAppService;
public MetaKeywordViewComponent(ITenantSiteDataAppService tenantSiteDataAppService)
{
_tenantSiteDataAppService = tenantSiteDataAppService;
}
public async Task<IViewComponentResult> InvokeAsync()
{
return View("/Pages/Shared/Components/Head/MetaKeyword.cshtml",
await _tenantSiteDataAppService.GetSiteDataAsync());
}
}
In addition, you can refer https://github.com/abpframework/abp/blob/42f37c5ff01ad853a5425d15539d4222cd0dab69/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/PageAlerts/PageAlertsViewComponent.cs
I am creating one phonegap application using Libstreaming for Video and Audio streaming. I have login and Home screen. On Home screen, there is a button "Start Streaming", on click of this button It launches the camera to start streaming which sends audio and video streams to WOWZA media server. The camera preview has one surface view on which video is getting played.
The camera preview has one Back button over SurfaceView to back on Home screen. My issue is that, On click of back button Camera preview should be destroyed and It should redirect to Home screen (Navigation from Android SurfaceView to HTML page).
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/surface_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:background="#android:color/black" >
<!-- Below surface view is used to to send rtsp audio+video stream to wowza server -->
<net.majorkernelpanic.streaming.gl.SurfaceView
android:id="#+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
<!-- button to halt the camera preview and go back on to the main screen -->
<Button
android:id="#+id/btnGoBack"
android:layout_width="60dp"
android:layout_height="40dp"
android:visibility="visible"
android:text="Back"
android:layout_alignTop="#+id/surface_view"
android:layout_alignParentLeft="true"
android:textSize="14dp"
/></RelativeLayout>
I have done it myself. It looks big but quite simple. All you need to do is, define a click method of back button (which is on the SurfaceView) in your activity class (Not MainActivity as follows-
public class LiveStreamingActivity extends Activity implements RtspClient.Callback, Session.Callback, SurfaceHolder.Callback {
private static SurfaceView mSurfaceView;
private Button btnGoBack;
private SurfaceHolder mHolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
if (!LibsChecker.checkVitamioLibs(this))
return;
mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
btnGoBack = (Button) findViewById(R.id.btnGoBack);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
/* click listener of back button */
btnGoBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
MainActivity.isFirstTime = true;
/* on click of back button finish the current activity
* which will destroy the surfaceview and will go back on MainActivity
* by referring the Android Activity lifecycle, OnResume() method of MainActivity
* would be called where you can call javascript function directly.
*/
finish();// callback lifecycle: "onPause", "onStop", and at last "onDestroy"
} catch (Exception e) {
e.printStackTrace();
}
}
});
}}
MainActivity.java:
You have to declare a field ("isFirstTime = false") to put a logic for calling javascript function in OnResume() method. (For better understanding please refer Android activity lifecycle).
public class MainActivity extends CordovaActivity {
public static boolean isFirstTime = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadUrl(launchUrl);
}
#Override public void onResume(){
super.onResume();
System.out.println("onResume main activity");
if(isFirstTime){System.out.println("Inside onResume");
loadUrl("javascript:launchProfile()");
}
}
#Override public void onPause(){
super.onPause();
System.out.println("onPause main activity");
isFirstTime = false;
}}
Javascript Function:
I am using AngularJS. So I have to get the $location object to inject the path of profilePage.
function launchProfile(){
var e = document.getElementById('loginScreen');/*'loginScreen' is login form id */
var $injector = angular.element(e).injector();
var $location = $injector.get('$location');
$location.path("/profilePage");}
app.js (Angularjs routing):
vcApp = angular.module('VCMobApp', ['ngRoute']);vcApp.config(['$routeProvider', function ($routeProvider){
$routeProvider.when('/', {templateUrl: 'screens/login.html', controller: 'loginPageCntrl' });
$routeProvider.when('/profilePage', {templateUrl: 'screens/profilePage.html', controller: 'profilePageCntrl'});
$routeProvider.otherwise({ redirectTo: '/' });}]);
In case you are not using AngularJS, then directly you can call your html page using window.location.href='../profilePage.html' inside launchProfile() function itself (skip angularjs code then).
I'm trying to test that the model returned from my Nancy application is as expected. I have followed the docs here but whenever I call the GetModel<T> extension method it throws a KeyNotFoundException.
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
I know what the error means but I'm failing to see why it's being thrown.
Here's my module
public class SanityModule : NancyModule
{
public SanityModule()
{
Get["sanity-check"] = _ => Negotiate.WithModel(new SanityViewModel { Id = 1 })
.WithStatusCode(HttpStatusCode.OK);
}
}
my view model
public class SanityViewModel
{
public int Id { get; set; }
}
and here's my test
[TestFixture]
public class SanityModuleTests
{
[Test]
public void Sanity_Check()
{
// Arrange
var browser = new Browser(with =>
{
with.Module<SanityModule>();
with.ViewFactory<TestingViewFactory>();
});
// Act
var result = browser.Get("/sanity-check", with =>
{
with.HttpRequest();
with.Header("accept", "application/json");
});
var model = result.GetModel<SanityViewModel>();
// Asset
model.Id.ShouldBeEquivalentTo(1);
}
}
Debugging this test shows that the module is hit and completes just fine. Running the application shows that the response is as expected.
Can anyone shed some light on this?
Thanks to the lovely guys, albertjan and the.fringe.ninja, in the Nancy Jabbr room we've got an explanation as to what's going on here.
TL;DR It makes sense for this to not work but the error message should be more descriptive. There is a workaround below.
The issue here is that I am requesting the response as application/json whilst using TestingViewFactory.
Let's take a look at the implementation of GetModel<T>();
public static TType GetModel<TType>(this BrowserResponse response)
{
return (TType)response.Context.Items[TestingViewContextKeys.VIEWMODEL];
}
This is simply grabbing the view model from the NancyContext and casting it to your type. This is where the error is thrown, as there is no view model in NancyContext. This is because the view model is added to NancyContext in the RenderView method of TestingViewFactory.
public Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
// Intercept and store interesting stuff
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWMODEL] = model;
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWNAME] = viewName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULENAME] = viewLocationContext.ModuleName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULEPATH] = viewLocationContext.ModulePath;
return this.decoratedViewFactory.RenderView(viewName, model, viewLocationContext);
}
My test is requesting json so RenderView will not be called. This means you can only use GetModel<T> if you use a html request.
Workaround
My application is an api so I do not have any views so changing the line
with.Header("accept", "application/json");
to
with.Header("accept", "text/html");
will throw a ViewNotFoundException. To avoid this I need to implement my own IViewFactory. (this comes from the.fringe.ninja)
public class TestViewFactory : IViewFactory
{
#region IViewFactory Members
public Nancy.Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
viewLocationContext.Context.Items[Fixtures.SystemUnderTest.ViewModelKey] = model;
return new HtmlResponse();
}
#endregion
}
Then it is simply a case of updating
with.ViewFactory<TestingViewFactory>();
to
with.ViewFactory<TestViewFactory>();
Now GetModel<T> should work without needing a view.
I need to know in a helper in a CakePHP application if the device is mobile, I would love to use $this->RequestHandler->isMobile(), but the request handler component is not available in helpers. Any ideas?
Thanks!
You can import the class and use it anywhere in the framework like so:
App::import('Component', 'RequestHandler'); // import class
$requestHandler = new RequestHandlerComponent(); // instantiate class
$isMobile = $requestHandler->isMobile(); // call method
var_dump($isMobile); // output: bool(true) or bool(false)
(Tested from helper and gives correct results for Firefox and iPhone)
Also, any options you set in the Controller::helpers property will be passed to the helper:
class AppController extends Controller {
public $components = array(/*...*/, 'RequestHandler');
public $helpers = array(/*...*/, 'MyHelper');
public function beforeFilter() {
$this->helpers['MyHelper']['mobile'] = $this->RequestHandler->isMobile();
}
}
You can catch the options array in your helper's constructor:
class MyHelper extends AppHelper {
protected $_defaultOptions = array('mobile' => false);
public function __construct($options) {
$this->options = array_merge($this->_defaultOptions, $options);
}
}
The accepted answer suggests using a component inside a helper which should be avoided as components are for use solely in controllers and will result in errors as mentioned by Anupal.
The simple solution is to use the CakeRequest class that RequestHandlerComponent uses. So in your helper you can do:-
App::uses('CakeRequest', 'Utility');
$isMobile = (new CakeRequest())->is('mobile');