Extend mobile view in Kendo UI Mobile? - javascript

It doesn't seem possible to extend the view for mobile. I would like to do so because I can predefine some options and behavior. I have create a sample here illustrating the problem, which gives me an error of:
Your kendo mobile application element does not contain any direct child elements with data-role="view" attribute set. Make sure that you instantiate the mobile application using the correct container.
JavaScript:
kendo.mobile.ui.plugin(kendo.mobile.ui.View.extend({
init: function (element, options) {
kendo.mobile.ui.View.fn.init.call(this, element, options);
},
options: {
name: 'ViewCustom'
}
}));
$(function () {
new kendo.mobile.Application(document.body);
});
HTML:
<section data-role="layout" data-id="default">
<header data-role="header">
<div data-role="navbar">My App</div>
</header>
<footer data-role="footer">
<div data-role="tabstrip">
Home
</div>
</footer>
</section>
<div id="home" data-role="viewcustom" data-layout="default">
Welcome to the home page!
</div>
http://jsfiddle.net/basememara/67RZN/
Kendo support simply said it's not supported - the mobile application does not recognize the descendants and does not initialize them upon start. This is a huge extensibility roadblock for mobile, so I've been poking around the source code to see where this is hard coded and I think the change will be somewhere in ViewEngine in kendo.mobile.view, possibly in _hideViews. I also see some hard coded views in kendo.mobile.pane. So I think this will be a big hack of the source code to get it working.
My question is there a way to extend the view without creating a new class, such as using prototype to extend kendo.mobile.view? Any help, experience, or insight will be greatly appreciated!

Instead of relying on Kendo to find the initial view to display, which will search specifically for data-role="view" you can instead programmatically tell it the initial view:
new kendo.mobile.Application(document.body, {
initial: "home"
});
I updated your example (and clicking the "Home" button also navigates to a second view just to make sure that worked as well).

Related

Can I use a JQuery plugin from within an angularjs directive?

I'm quite new to javascript in general. I've spent the past couple of weeks building a front end with Angular.js.
I have a number of directives I've defined that sit on my page, Angular has been great for this.
Here's what my main page looks like:
<body class="body" ng-controller="OverviewController as overview" font-size:1em>
<sidebar-menu ng-controller="PanelController as panel"></sidebar-menu>
<div id="content" >
<div>
<div class="list-group">
<div class="list-group-item" ng-repeat="site in overview.sites" ng-click="">
<div class="item-heading">
<h3>{{site.name}}</h3>
<p>Address: {{site.address}}</p>
Click Here
</div>
<installationsite-panels ng-controller="PanelController as panel"></installationsite-panels>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('.paulund_modal').paulund_modal_box();
});
</script>
</body>
Note the javascript function to call a modal box at the bottom, using this tutorial.
I've spent the past few days trying different tutorials to get modals to work in my webapp, but with no success. I think it's down to my lack of understanding of Angular and Javascript in general.
In any case, I've managed to get this tutorial to work using JQuery, and when I click on the link, the modal opens as expected.
However, I don't want to call this modal from here. I want to call it from a directive that's embedded within the <installationsite-panels> directive in the above code, which looks like this (just a single section shown here):
Device Statuses
<div>
<div class="device-icon-group">
<div class="device-type1-icons" ng-click="panel.showDevices(3)" ng-show="showtype1Red"><img src="img/type1red.png" style="width:50%; height:50%;"/></div>
<div class="device-type2-icons" ng-click="panel.showDevices(3)" ng-show="showType2Red"><img src="img/type2red.png" style="width:50%; height:50%;" /></div>
</div>
<div class="service" ng-click="panel.showDevices(3)" ng-show="showService">
<b>{{panel.getServiceDeviceCount()}} device needs servicing</b>
</div>
<div ng-show="showServiceList">
<device-list-service></device-list-service>
</div>
</div>
The directive <device-list-service> shows a list of items like so:
<div ng-controller="DevicesController as deviceList" font-size:1em >
<div id="device-list-group">
<div id="device-list-group-item" ng-click="" ng-repeat="device in deviceList.devicesService">
<div ng-class="device.status"><img src="{{(device.type == 'type1') ? 'img/type1white.png' : 'img/type2white.png'}}"> </div>
<div class="device-params">
<b>ID: </b> {{device.id}}<br />
<b>Type: </b> {{device.type}}
</div>
<div class="device-params">
<b>Location: </b> {{device.location}}<br />
<b>Action: </b> {{device.action}} <br />
</div>
</div>
</div>
</div>
I want to show the modal when the user clicks on one of the list-group-item 's, and display some data relating to that item.
The modal works fine from the top level in the main app, but I cannot call it from within any of the directives. How can I do this?
Is it possible, or do I need to scrap my JQuery modal and do it the Angular way, which hasn't worked for me for the past few attempts.
Don't use jquery modals. You can, but you shouldn't.
Instead, I recommend using Angular UI, which has a pretty usable modal implementation: https://angular-ui.github.io/
Second alternative: if you don't like Angular UI, then use AngularJS + Bootstrap, and create your own custom directives
Third alternative: Use jQuery.
If you still want to go with the 3rd alternative, despite my advice against it, then here is how you do it:
var app = angular.module('app', []);
app.directive('modal', function($http, $timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
$timeout(function() {
element.paulund_modal_box();
}, 0, false);
}
};
});
Usage:
<div modal></div>
Some explanation is needed here.
Why is the $timeout service necessary? jQuery plugins often require the DOM to be fully loaded in order to work properly. That is why most jQuery plugins are wrapped inside of a $(document).ready block. In AngularJS there is no concept of DOM ready, and there is no easy way in AngularJS to hook into the event. However, there is a well-known hack, which is to use the $timeout service. In Angular there are three phases:
1. compile - Angular walks the DOM tree looking for directives
2. Link - Angular calls the link function for each directive to setup watch handlers.
3. Render - Angular updates the views
Using $timeout within the Link function queues the $timeout function to be executed until after the current closure is done executing. It just so happens that the Render phase is within the current closure's scope of execution. Hence, the $timeout function will execute after the render phase, when the DOM has been loaded.
Mixing JQuery and Angular in that way is maybe a little messy, but sometimes you do want to use a well-built component. You could try to find a similar modal in Angular - angular-modal - or you could try and build the component into your Angular directive itself - jQuery Plugins in AngularJS

Kendo UI - Localize application

How does one localize a pure front-end application that uses a framework such as Kendo UI ?
I mean, it's possible to do something like this:
$(document).ready(function(){
$("#myText").html(<grab text based on language>);
});
But then, if I have a listview and want to localize its title:
<div id="tabstrip-expenseaccounts" data-role="view">
<ul data-role="listview" data-style="inset" data-type="group">
<li id="expenseaccounts-listview-title">
abcde
<ul>
...
</ul>
</li>
</ul>
</div>
Becomes:
...
<li id="expenseaccounts-listview-title" class="km-group-container">
<div class="km-group-title">
<div class="km-text">abcde</div>
</div>
<ul class="km-list">
...
</ul>
</li>
...
I need to inspect the generated code and do something like:
$(document).ready(function(){
$("#expenseaccounts-listview-title.km-group-container div.km-group-title div.km-text").html(<grab text based on language>);
});
It works fine, but that doesn't seem like a clean solution to me.
Any advice ? Thanks!
For KendoUI there some language packs available on GitHub here. This other stakoverflow question should give you a headstart. With this, all you have to do is use the correct language pack and you're good to go. And if there is no language pack for your specific case, you can always roll your own.
Hope this helps.
While I have not found a solution proper to Kendo UI, here is the approach I went for to localize my mobile application. Note here that I am not talking about localizing widgets, I am referring to localizing every static aspect of the application: input placeholders, texts on buttons, headings, etc.
My mobile application only has one file, index.html, and whenever I want to navigate to a different page, i simply move to a different view. Since having multiple views in the same file is kind of a mess, I made one html file per view, and am dynamically loading them into the body (index.html has an empty body). Before appending the html which is retrieved using $.get for each view (at this point, it's a huge string), i am replacing text based on the current language (which is retrieved from the localstorage/cookie or from a default value).
example:
In my localization library:
_localization.localizeText = function(text, arr){
arr.forEach(function(item){
text = text.replace(item.name, getLang() == 1 ? item.replacement.en : item.replacement.fr);
});
return text;
}
In my login.html file:
<button>$$login-button$$</button>
And then in some javascript file which is included before the script in which the application is initialized:
var replacements = [];
replacements.push({
name: "$$login-button$$",
replacement: {
fr: "Connecter",
en: "Log In"
}
});
And then when i'm loading my files into the body:
$.when($.get("login.html"))
.done(function(p1){
var body = $("body");
body.append(localization.localizeText(p1[0], app.replacements));
});
Hope this helps anyone with similar issues!

Multiple layouts with Angular

I am building an Angular app and hitting a bit of a snag in how to handle the home page. The home page is 90% different - only the header stays the same - in there I have directives that show user login state for ex.
To make use of routing/templates etc I'd ideally like to have my ngview in the white area of sample shown - that all works fine - just not sure how to build the home page. It doesn't need an ngview area persay since it's the only one of it's kind. I don't want to make it as a second apps however as that seems wasteful and would reload everything.
Googling this brings up suggestions of replacing the white area with a directive but then I think I would lose the whole routing/template benefit.
Alternatives I have seen have code to determine if on home and load a body CSS class etc but that is not ideal either as the content is so different.
UI Router is a possibility but I'd like to avoid prebeta stuff if possible.
Suggestions?
You could have this:
index.html:
<body>
...header..
<div ng-if="isHomePage()">
<div ui-view></div>
</div>
<div ng-if="!isHomePage()">
<div ng-include="'shell.html'"></div>
</div>
...footer..
</body>
home.html (with route '/')
...your home page html...
shell.html (any route different than '/')
<div>
<div>
<div ui-view></div>
</div>
<aside><aside>
</div>
finally, add isHomePage() to your root scope
$rootScope.isHomePage = function() {
return $location.path() == '/';
};

viewContentLoaded - Without duplicating code per each controller - AngularJS

Hey all I'm trying to get a feel for angular and have ran into a little snag.
I have a container structure like the following:
<div class="main-container" ng-view>
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
Before I implemented Angular I just had a simple script that would check the height of the window and set the height of the left column and right column divs accordingly.
With angular there is probably a better way to do this then attaching an event function to the window object. Basically I want to fire a function everytime a new view is rendered but not duplicate the below code in all of my angular controllers like so:
$scope.$on('$viewContentLoaded', setColumnHeight);
Any help would be appreciated. Thanks!
I've solved this problem in my app by having a root "Application Controller" at the top of the DOM tree. For example:
<body ng-controller='applicationController'>
...
<div class="ng-view"></div>
...
</body>
applicationController is always there, and can set up bindings on its scope when it is created.
How about putting that event listener on the root scope:
$rootScope.$on('$viewContentLoaded', setColumnHeight);
You could use something like this:
<div class="main-container" ng-view>
{{ setColumnHeight() }}
<!-- The below divs are constantly being
reloaded based on the current URL and it's associated view -->
<div class="left-col">
</div>
<div class="right-col">
</div>
</div>
and it will check the height every time a render is made, however, this seems to be a bit over processing.
The best approach would be to only update the height from both columns when the height of one of them changes. For that you could use DOM Mutation Observers, however they are not yet available on all browsers. If that's not a problem for you, check the mutation-summary lib.
If you are using jQuery you can also try this: https://github.com/jqui-dot-net/jQuery-mutate (examples here).

ExpressionEngine putting Javascript on a page

I am a super beginner to EE and was literally thrust into managing my company's website that is built in EE without training. I'm not a programmer, I'm a designer, so it's been taking me awhile to plug through this. So I might need some dumbed down language :)
I want to create a page that has some Javascript on it. Do I need to create a new template JUST so I can put some javascript on it? And how do I communicate to EE that I want the page I created to go with that template?
I duplicated the page/index template and renamed it to clinician-map (the same name of the page I created in the publisher). EE didn't like that and the page subsequently broke. All I want to do is insert one javascript item, this seems way too inefficient for just one page. Help??
(using EE 1.6.8)
Here is my code from clinician-map template.
{assign_variable:my_weblog="page"}
{assign_variable:my_template_group="page"}
{embed="embeds/html_head" url_title="{segment_2}"}
{embed="embeds/html_styles"}
{embed="embeds/html_scripts"}
<?php include_once("analyticstracking.php") ?>
</head>
{exp:weblog:entries weblog="{my_weblog}" disable="categories|member_data|pagination|trackbacks" limit="1" sort="asc" }
<body class="{url_title}">
{/exp:weblog:entries}
<div id="wrapper">
{embed="embeds/html_headerPlusLeftNav"}
<div id="content">
<div id="contentMain">
{exp:weblog:entries weblog="{my_weblog}" disable="categories|member_data|pagination|trackbacks" limit="1" sort="asc"}
<h2>{title}</h2>
{page_body}
{/exp:weblog:entries}
<!--contactforminfo -->
{exp:weblog:entries weblog="{my_weblog}" disable="categories|member_data|pagination|trackbacks"}
{related_entries id="playa_contentcalloutitems"}
<div class="callout">
<h3>{title}</h3>
{callout_summary}
</div>
{/related_entries}
{/exp:weblog:entries}
{exp:weblog:entries weblog="{my_weblog}" disable="categories|member_data|pagination|trackbacks"}
{related_entries id="playa_contentfeatureditems"}
<div class="featuredContent">
<h3>{title}</h3>
{exp:word_limit total="50"}
{contentfeatured_summary}
{/exp:word_limit}{if contentfeatured_body!=""}<p><a href='{url_title_path='content-featured/'}' class='more'>Read More</a></p>{/if}
</div>
{/related_entries}
{/exp:weblog:entries}
</div>
{exp:weblog:entries weblog="{my_weblog}" disable="categories|member_data|pagination|trackbacks"}
<div id="contentSub">{related_entries id="playa_contentsubitems"}<div class="item {contentsub_bgcolor}">
{if contentsub_contenttype=="Text or Picture with Text"}
<h3>{title}</h3>
{exp:word_limit total="50"}
{contentsub_summary}
{/exp:word_limit}{if contentsub_body!=""}<p><a href='{url_title_path='content-sub/'}' class='more'>Read More</a></p>{/if}
{if:else}
<h3 class="imgHeader">{title}</h3>
{exp:html_strip convert="y" convert_back="none" keep="a,img"}
{contentsub_summary}
{/exp:html_strip}
{/if}
</div>{/related_entries}
{/exp:weblog:entries}
{embed="embeds/html_mailingListSignup"}
</div>
</div>
{embed="embeds/html_footer"}
</div>
</body>
</html>
At glance I can see a couple things that might be confounding you...
You started with a template called 'index' in the 'page' template group.
Looks like the 'page' template you are starting from is meant to display a single entry from the 'page' weblog.
So a request url might look something like this:
http://example.com/page/some_url_title
where 'some_url_title' is the 'url_title' value one of the entries in your 'page' weblog.
Now you have gone and duplicated the index template and called this new template 'clinician-map'.
So you would call an entry through this template at:
http://example.com/page/clinician-map/some_url_title
Now, notice that the first url had 2 segments, while the second had 3 segments?
That's not normally a big deal but the fellow who designed the index template did something that makes it problematic. He is taking the value of segment_2 and passing it through an embed.
So in the first example (index) we are passing the dynamic value "some_url_tile" while in the second example (clinician-map) we are passing "clinician-map". If the embedded template 'html_head' is expecting to get a valid url_title but instead gets the string 'clinician-map' you are likely going to get unexpected results.
Also I don't think we know enough about what you are trying to do to decide if creating a new template is the right approach here. It may be that what you actually need is a new weblog entry or perhaps just a dynamic value inside your existing template.
If it did turn out that a new template is the best approach you could fix the problem I have described by simply replacing segment_2 with segment_3, but I am by no means certain that that is the way you want to go.
I want to create a page that has some Javascript on it. Do I need to
create a new template JUST so I can put some javascript on it?
More specifics would be needed in order to give a solid recommendation but in almost every case, I recommend keeping JavaScript grouped together either in the <head></head> or ideally right before the closing </body> tag if you can get away with it.
Looking at your template code, it appears all the JavaScript is stored in the embeds/html_scripts page. I would add the JavaScript you need to that template. If you only want the JavaScript to appear for certain pages only, I would make use of a conditional (which I'll outline at the end of my answer).
And how do I communicate to EE that I want the page I created to go
with that template?
ExpressionEngine URLs (by default) are assembled as follows:
http://website.com/group/template/url_title
Therefore if you have a page with a url_title of "contact-us", and you wanted that page to use a template in site/pages, you could tell your page to use that template like so:
http://website.com/site/pages/contact-us
That url is obviously fine and dandy for blog articles and such, but it's not that pretty; so ExpressionEngine also enables you to construct "page" based navigation which creates navigation tree based url structures, such as:
http://website.com/contact-us
There are a few third party modules that make it easy to build page navigation such as:
devot-ee.com/add-ons/structure
Using Structure, you specify the default template for each channel and can override the template for each page as well.
I duplicated the page/index template and renamed it to clinician-map
(the same name of the page I created in the publisher). EE didn't like
that and the page subsequently broke. All I want to do is insert one
javascript item, this seems way too inefficient for just one page.
Help??
(using EE 1.6.8) Here is my code from clinician-map template.
There are a number of things I would do different in regards to the template code you provided; however, as a quick fix here's how I would add the one line of JavaScript,
1) Open the embeds/html_scripts template and add the following logic:
{if segment_2 == "my_page_url_title"}
<!-- javascript here -->
{/if}
Note: Here's how segments are determined:
http://website.com/segment_1/segment_2/segment_3
Okay. I ended up just creating a new webblog and new template group and finally it seems like it's working. My javascript is not, but I can figure that out.
Thank you so much for your patience with helping me!

Categories

Resources