converting Jquery to angular or making Jquery work in angular - javascript

I am new to angular and we are converting a set of screens based on jsp to angular. Initially we have written lot of code in Jquery. Converting them to angular is tedious task and thought of trying to see if we can make jquery work with angular. Here is teh code snippet that i am trying to make it work while it in Jquery.
$(document).ready(function() {
$("#ClickTask2").click(function() {
$(".ClickTask1").hide();
$(".ClickTask2").show();
});
});
Above is the piece of code I have in JQuery and i tried to make it work.
angular.element(document).ready(function() {
$("#ClickTask2").click(function() {
$(".ClickTask1").hide();
$(".ClickTask2").show();
});
});
Can anyone tell me how i could make it work with minimal changes to the above one and rest of the jqueries?

You can convert many jquery features over to Angular by simply changing the $() method to angular.element() e.g.
$('#output').html('<h1>Title</h1>');
You could convert this to:
angular.element('#output').html('<h1>Title</h1>');
However not all function work, and some are renamed e.g.
$("#output").click(function() { console.log('Hi'); });
Would need to be changed to:
angular.element('#output').on('click', function() { console.log('Hi'); });
You can find a full list of the supported functions here:
https://docs.angularjs.org/api/ng/function/angular.element

like said Luis Masuelli on the comments read the basis of Angular. a quick lesson
app.js
function TaskCtrl($scope) {
$scope.selectedTask = null;
$scope.tasks = [/* ... */];
$scope.onClickTask = function(task) {
$scope.selectedTask = task;
}
$scope.isSelected = function (task) {
return task === $scope.seletectedTask;
}
}
$scope it is a special variable, it is injected by Angular to controllers and serves to communicate the controller with the view among other things. A controller can be any function and the name does not matter.
main HTML
<ul data-ng-controller="TaskCtrl">
<li data-ng-repeat="task in tasks" data-ng-click="onClickTask(task)">
{{task.title}}
<div data-ng-show="isSelected(task)">{{task.description}}</div>
</li>
</ul>
data-ng-controller tells to Angular "this is the controller" for this tag and her children. The other directives are pretty explanatory, but the documentation you left it more clearly.
Of course I am assuming that your tasks has the following structure:
{
title: "...",
description: "..."
}
in your html you need include the angular.js, the previous js and a directive to tell angular that this is a application
<!DOCTYPE html>
<html>
<head></head>
<body data-ng-app>
<!-- main HTML -->
<script src="angular.js"><script/>
<script src="app.js"><script/>
</body>
</html>
the data- prefix on each directive is not necessary but as angular "extend" HTML and these are not native attributes, I use them to place custom attributes as "ng-repeat", "ng-controller", "ng-app" etc. They are called directives
Remember, with Angular you need not manipulate the DOM directly as is done with jQuery, except for some special exceptions

Related

Is it possible to use JQuery includes with Angular Includes?

I am working on an application that utilizes both Jquery and AngularJS includes, however Angular does not seem to execute after Jquery has included a file that has AngularJS markup. Jquery is including the "top_nav.html" template and inside this template there lives a angluar ng-include calling cart.html". I need to figure out how to get the angular code to execute after being included by jQuery.
<div id="topNav"></div>
<script>
//outside the document ready statment
$('#topNav').load('includes/top_nav.html');
<script>
top_nav.html:
<div>
...
<div ng-controller="shoppingCart"
class="shopping-cart"ng-include="'includes/cart.html'"></div>
</div>
The jquery load does an ajax request. When the ajax is resolved, the angular have already been bootstrapped (assuming you use ng-app directive), so the html chunk that have been dynamically loaded was not bootstrapped by angular.
So, I guess that on the callback of the jquery load, you need to manually bootstrap angular passing <div id="topNav"></div> as the context. Something like this:
var topNav = $( "#topNav" );
topNav.load( "includes/top_nav.html", function() {
angular.bootstrap(topNav.find("> div")[0], ['topNavAngularModule']);
});
Note: I'm not sure, sorry, I haven't tested it, but I think it might only work if #topNav is located outside ng-app.

How does childscope work on an ng-if statement? Specifically in a <SELECT> element

NOTE: I'm a new member here so I couldn't directly comment and ask for clarification.
So, my question is: How can I work around ng-if creating a child scope for a select element?
I have the following code:
HTML
<select id="project-select"
ng-if="projects.length > 0"
ng-options="project.name for project in projects"
ng-model="currentProject"
ng-change="broadcastChange('project-changed', currentProject)">
</select>
And my controller is set up in the following format:
function Controller() {
//Do code stuffz
}
angular
.module('app')
.controller('Controller', Controller);
I learned from this post that the "ng-if" is creating a child scope.
So even when the model changes, this part stays the same because it is a primitive value: (name is just a string)
<div id="current-project" class="pull-left">
<strong>Project: </strong>{{currentProject.name}}
</div>
Furthermore in the aforementioned post there were a couple options.
a. Simply change to this: ng-model="$parent.currentProject" which feels a little hacky
b. Set the object value in the controller, which I'm not entirely sure how to do. I feel like it's an easy fix, but I'm somehow overcomplicating it.
Anyway, for now I simply changed ng-if to ng-show and that's solved the problem. However, I am trying to understand Angular more deeply and I feel like this issue could be explained a little bit better to me. Thanks in advance!
What you will find with Angular scope variables is: always use a dot.
That's the mantra from the excellent ng-book
In your case, what this means is this:
You have this code:
<select id="project-select"
ng-if="projects.length > 0"
ng-options="project.name for project in projects"
ng-model="currentProject"
ng-change="broadcastChange('project-changed', currentProject)">
</select>
Which means that you are binding to a $scope variable called $scope.currentProject.
Because of the mysterious and awesome way that javascript works, this does not get updated when you are inside of a child scope.
Thankfully, the solution is actually quite simple. Instead, create an object like so:
$scope.myData = {
currentProject: ''
}
And in your markup, bind to that like so:
<select id="project-select"
ng-if="projects.length > 0"
ng-options="project.name for project in projects"
ng-model="myData.currentProject"
ng-change="broadcastChange('project-changed', myData.currentProject)">
</select>
And voila. It will update, even though it's in a child scope.
This is actually quite useful, because you now have a way to "meaningfully" group variables together. Here's some other pseudo-code to demonstrate what I mean:
$scope.projectData = {
currentProjectID: 1,
currentProjectTitle: 'My Cool Project',
projects: [
{id: 1, name: 'My Cool Project'},
{id: 2, name: 'Another Project'}
],
someOtherProperty: false
// ...etc....
}
As a side-note, this section of this article might be helpful: http://docstore.mik.ua/orelly/webprog/jscript/ch11_02.htm#jscript4-CHP-11-SECT-2.1
If all you want to do is show/hide the select element based on the projects in your 'Controller' controller scope, then ng-show is the right way to go here. In my experience, I've used ng-if when I'm conditionally loading a larger "partial" view containing numerous controls where I felt a separate scope was necessary to avoid having a very large scope (or to facilitate re-use).
You are correct. Do not use $parent in any production Angular apps. It makes your model dependent on the structure of your view, which makes your code hard to refactor and less modularized.
Binding to object properties is the way to go, as you suggested in your "b" answer. The recommended way to do this in the latest version of Angular 1.x is by using the "controller as" syntax. This method makes use of "prototypical inheritance" in javascript. There is a good explanation on this here: http://javascript.info/tutorial/inheritance
I created a plunker for you to demonstrate how binding to object properties works in nested scopes. take a look at the "controller as" syntax". also, try changing the value of ctrl.testBinding in the input, you will see that reflected in the ng-if child scope. I will try to find some links to explain this in more detail.
https://plnkr.co/edit/Gx5xbkJXgzjPSG8kajPR?p=preview
<!DOCTYPE html>
<html >
<head>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="testApp">
<div ng-controller="testCtrl as ctrl">
<input ng-model="ctrl.testBinding" type="text"/>
<button ng-click="ctrl.toggle()">toggle show</button>
<div ng-if="ctrl.show">
{{ ctrl.testBinding }}
</div>
</div>
</body>
</html>
//script.js
function testController($scope) {
var vm = this;
vm.show = true;
vm.toggle = function(){
vm.show = !vm.show
}
}
angular
.module('testApp', [])
.controller('testCtrl', testController);

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!

AngularJS - Run directives explicitly

I'm new to AngularJS and I'm struggling with the following issue.
I need to implement a 3 step workflow as follows:
Make a call to a web service that returns a list of strings. For example, ["apple", "banana", "orange"], etc. I intercept the response and add the angle brackets around each of these strings before I send it to the Views.
For each of the string returned by the service, I have to render
<apple />
<banana />
<orange />
Finally, get the actual AngularJS directive corresponding to each of those strings to "execute" (not sure what the right word is) and replace the elements above with the content from the templateUrl property as mentioned in each of their respective directives.
Right now, I'm doing Step 1 and Step 2 above using AngularJS. But I understand that they can be done using plain JavaScript using AJAX calls.
My problem is that the directives don't get "run" or "executed" and I have these tags displayed as plain text on the page -
<apple />
<banana />
<orange />
etc.
How do I tell Angular to replace the custom tags with the actual content from their templates?
Thanks for your help.
UPDATE: Here's what the code looks like:
<div class="content" ng-controller="mainController">
<ul class="feeds">
<li ng-repeat="fruit in fruits">
<div ng-controller="fruitSpecificController"> {{fruit}} </div> <!-- This renders <apple />, <banana />, etc. -->
</li>
</ul>
</div>
Also note that each fruit can have its own controller. In the code above, I say "fruitSpecificController", but ideally that would also be generated at runtime. For example, "appleController", "orangeController", etc. and yes, they'll be child controllers of the parent "mainController".
You can use the compile method, but there is a built in directive that will do this for you - if you are willing to load in via a URL.
ng-include
Using ng-include="'/path/to/template.html'" - the evaluated expression URL will be requested and added to the DOM as a child (compiled for you).
You can also cache the templates using $templateCache (if you want to request multiple templates at the same time or cache it for multiple includes).
That would look something like this:
$templateCache.put(/path/to/template.html, 'apple html string');
custom directive (with $compile)
Otherwise, if you want to load in and compile a string - use a directive inside of a ng-repeat.
.directive('unsafeHtmlCompile', function($compile){
return {
link: function(scope, element, attrs){
scope.$watch(attrs.unsafeHtmlCompile, function(val){
if(val !== undefined){
element.html('');
var el = angular.element(val);
element.append(html);
$compile(el)(scope);
}
});
}
}
}
Remember to remove the watcher, if your data won't change :-)
You probably just need to use the $compile service. The docs aren't super helpful but the gist is that you call $compile, passing in the DOM element (in your case the parent of your directives). That returns a function that you then execute, passing in the scope that you want to use ($rootscope is probably safe).
$compile(element)($rootScope);

Are'nt we Allowed to write html codes if we use backbone.js?

I am learning backbone.js and I have seen some examples like this one.Here the user has not written much html codes inside the editor.html.Only 4 lines of code.But for colour change,size change etc he has done inside editor.js
Please help me understand what all codes we need to keep inside .html file
<div id="page" style="width:2000px;height:2000px;">
<button id="new-rectangle">New Rectangle</button>
<button id="new-circle">New Circle</button>
</div>
You should aim to put all your html in .html file(s). As an app grows, it will help you to keep them separate. The example you link to is a 'simplified' version - this is not how you would structure things in an actual app. You would load html from templates in the render function. A (though this is also simplified as I am relying on script tags) pattern would be:
HTML file:
[...SOME HTML...]
<script type="text/html" id="template-contact">
<div class='contact'>
<h1>Here's my template code</h1>
<strong>name</strong>
<span>email</span>
</div>
</script>
Then in your Backbone view render function:
render: function() {
template: _template($('#template-contract').html(),
this.$el.html(this.template());
return this;
}
Then somewhere else in your Backbone code you create a new instance of the view and render it.
var example = new view_name();
example.render(); //This loads the html template
If you need to dynamically load the html from a server, you can use underscore (or whichever template engine you are using) tags in your template '<%>' and use models. This is best explained in Addy Osmani's book Developing Backbone.js Applications which, incredibly, is free. Here's the link to the relevant section
Whatever you wants to display on the browser you can keep it in .html file and logic to update the dom on run time should be in .js file.

Categories

Resources