Append / add, text and function to a div's content - javascript

I'm currently working on a AngularJS based application. I'm using the 'pascalprecht.translate' library to create a multi-language application. For more information on that please see this link. While creating my application i've created a dynamic switch of page titles. this switch reads the route name from the $routeProvider and adds a corresponding title to the <header>. See the example below:
// Pages configuration
myApp.run(['$rootScope', '$route', function($rootScope, $route) {
$rootScope.$on('$routeChangeSuccess', function() {
document.title = $route.current.title;
var title = document.getElementsByTagName("title")[0].innerHTML;
var leftSvg = document.getElementById('leftsvg');
var rightSvg = document.getElementById('rightsvg');
// start responsive elements
$("footer").removeClass("hidden-xl-down");
$("#header").removeClass("hidden-xl-down");
$("#leftheaderblock").removeAttr('class');
$("#rightheaderblock").removeAttr('class');
$(".activefooter").removeAttr('class');
$("#homepageback").removeClass("hidden-xl-down");
$("#rightsvg").addClass("hidden-xl-down");
$("#leftsvg").addClass("hidden-xl-down");
$("body").removeAttr('class');
$("body").addClass(title);
if (title === 'login') {
$("footer").addClass("hidden-xl-down");
$("#header").addClass("hidden-xl-down")
}
else if (title === 'productpage') {
$("#homepageback").addClass("hidden-xl-down");
$("#homesvg").addClass("activefooter");
$("#leftheaderblock").addClass("col-55");
$("#rightheaderblock").addClass("col-45");
$('#leftheadertext').text('Alle producten');
$('#rightheadertext').text('Bestelling');
$("#rightsvg").removeClass("hidden-xl-down");
$("#leftsvg").removeClass("hidden-xl-down")
}
});
}]);
The html
The <html> is some simple div's in an index.html file. Below you'll see the example of the rightheaderblock.
<div id="rightheaderblock">
<div class="bc-f3f3f3 justify-content-center toptext d-flex align-items-center headerblock">
<span id="rightheadertext"></span>
</div>
</div>
The question
Using 'pascalprecht.translate' gives access to the possibility of creating a multiple language application with your own language library's in JSON format. See the example below:
var myApp = angular.module('myApp',['ngRoute','pascalprecht.translate','ngSanitize']);
var mypagetitle = document.getElementsByTagName("title")[0];
myApp.config(function ($routeProvider, $locationProvider, $translateProvider) {
$locationProvider.hashPrefix('');
$routeProvider
.when('/', {
templateUrl: 'views/login_view.html',
title: 'login'
})
.when('/productpage', {
templateUrl: 'views/productpage_view.html',
title: 'productpage'
})
.when('/payorder', {
templateUrl: 'views/payorder_view.html',
title: 'payorder'
});
$translateProvider
.translations('en', {
'Opslaan': 'Save',
'Alle producten': 'All products',
'Bestelling': 'Order',
})
.translations('nl', {
'Opslaan': 'Opslaan',
'Alle producten': 'Alle producten',
'Bestelling': 'Bestelling',
});
$translateProvider.useSanitizeValueStrategy('sanitize');
$translateProvider.preferredLanguage('nl'); // standaard taal bij openen
// configures staticFilesLoader
// configures staticFilesLoader
});
myApp.controller('mainCtrl', function($http, $scope) {
$scope.text = "hi";
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="main" ng-controller="mainCtrl">
<div id="rightheaderblock">
<div class="bc-f3f3f3 justify-content-center toptext d-flex align-items-center headerblock">
<span id="rightheadertext">
{{text}}
</span>
</div>
</div>
<div class="bodyTests">
<p> {{ "Bestelling" | translate }}
</div>
Above you're able to look at a simple example of how the 'tranlate' function works. by adding | translate to a string and defining that string to a .translations() section i'm able to create the translations.
Looking back at the // Pages configuration above you're able to see that i'm using if/else statements to check for the page title and add .text() and classes to a div by current page title.
The issue i'm having is passing the | translate section of e.g. {{"bestelling" | translate}} from the if/else statement to the view. So passing the following line:
$('#rightheadertext').text('Bestelling');
To the page isn't a problem. But adding
$('#rightheadertext').text('{{ Bestelling | translate }}');
gives me the full string in the view:
{{ Bestelling | translate }}
i've tried multiple different functions like .val() and append(). But neither seems to work. The result i would like is to add the following structure to the view:
{{ "string" | translate // call }}
If you have any questions or remarks on my question please let them know in the comments below.
As always, thanks in advance!

How about this...
<p> {{ $root.text1 | translate }}</p>
Then in your code, in the if/else...
if (...) {
$rootScope.text1 = 'Bestelling';
} else {
$rootScope.text1 = 'Opslaan';
}

Related

AngularUI Bootstrap Carousel not working properly when binding HTML content with $compile

AngularUI Bootstrap version ^2.4.22
AngularJS version 1.6.4
Angular Sanitize version ^1.6.1
I'm having trouble using AngularUI Bootstrap's Carousel plugin. In my scenario, i need to read an external file containing some template paths, and load each of them as a slide. See example below:
index.html (where directive is being called)
<body id="body" ng-app="homePage">
<div id="miolo">
<div example-directive class="ng-hide"></div>
<div banner-rotativo></div>
<div id="menu-footer"></div>
</div>
</body>
banner-rotativo.directive.js - Basically, in this directive, I have a template following the structure of AngularUI Bootstrap's demo, and i'm binding the response data to $scope.slides array. When i push into htmlContent property the $compile(objResponseInner)($scope) result, the carousel behavior works okay, but it renders [[object HTMLDivElement]] and things like that as an item.
angular.module('homePage')
.directive('bannerRotativo', ['$compile', '$http', 'moduleUrl', '$templateRequest', function ($compile, $http, moduleUrl, $templateRequest) {
return {
template: '<div style="height: 305px" ng-controller="bannerHomeController" class="" >\
<div uib-carousel active="active" interval="myInterval" no-wrap="noWrapSlides">\
<div uib-slide ng-repeat="slide in slides track by slide.id" index="slide.id">\
<div ng-bind-html="slide.htmlContent">\
</div>\
</div>\
</div>\
</div>',
link: function (scope, element, attributes, controller) {
//Carousel
scope.myInterval = 5000;
scope.noWrapSlides = false;
scope.active = 0;
scope.slides = [];
var intCurrentIndex = 0;
$http({
method: 'GET',
url: moduleUrl.getUrl('homepage', '../config/banner-rotativo.conf')
}).then(function success(objResponse, status, headers, config) {
var objData = objResponse.data;
if (objData.slides) {
angular.forEach(objData.slides, function (objItem, strObjectName) {
var strTemplatePath = moduleUrl.getUrl('homepage', '..' + objItem.caminho);
if (strTemplatePath) {
$templateRequest(strTemplatePath).then(function success(objResponseInner) {
var objContent = $compile(objResponseInner)(scope);
scope.slides.push({
htmlContent: objContent,
id: intCurrentIndex++
});
});
}
});
}
});
}
}
}]);
banner-rotativo.conf
{
"slides": {
"banner-ex-one": {
"titulo": "exone",
"caminho-imagem": "assets/one.jpg",
"caminho": "/html/components/banner-rotativo/banner-ex-one.view.html"
},
"banner-ex-two" : {
"titulo": "extwo",
"caminho-imagem": "assets/two.jpg",
"caminho": "/html/components/banner-rotativo/banner-ex-two.view.html"
},
"banner-rav" : {
"title": "rav",
"caminho-imagem": "assets/rav.jpg",
"caminho": "/html/components/banner-rotativo/banner-rav.view.html"
},
"banner-aviso" : {
"title": "Quadro de comunicações 1",
"caminho-imagem": "assets/aviso.jpg",
"caminho": "/html/components/banner-rotativo/banner-aviso.view.html"
},
"banner-custom" : {
"title": "Quadro de comunicações 2",
"caminho-imagem": "assets/custom.jpg",
"caminho": "/html/components/banner-rotativo/banner-custom.view.html"
}
}
}
Loaded template example:
<div id="frameOne" ng-controller="slideOneController" class="varejo-clique-promocao-one" title="Conteúdo Varejo - Quadro One">
<div class="item">
<div id="dados">
<!-- Imagem banner one -->
<img id="one" ng-click="enviarFormOne()" class="one" alt="" ng-if="1==1" ng-src="caminhoImagem"
/>
<!-- End imagem banner -->
<span ng-if="hasText">{{bannerText}}</span>
</div>
<div id="excecao" class="excecao" ng-if="typeof(one.excecao) !== 'undefined'">
DEU EXCECAO
</div>
<div class="carousel-title" id="tituloOne" ng-if="1==1" title="{{bannerTitle}}">
{{bannerTitle}}
</div>
</div>
Some important points:
I'm using $compile because my injected templates have controllers too. If i don't use it, my controllers aren't processed. When i simply insert the HTML without the $compile, it renders okay.
What's wrong?
The problem is that ng-bind-html expects html string and you are giving it the result from $compile that is actually an element object. You could take the HTML string from the compiled element and pass that instead, but you would probably run into all kind of trouble with that.
But you can actually just skip the hassle with $compile by using ngInclude instead of ng-bind-html. It will handle both the template request and the compilation for you.
So instead of requesting and compiling strTemplatePath, store that to the slide list:
var strTemplatePath = moduleUrl.getUrl('homepage', '..' + objItem.caminho);
if (strTemplatePath) {
scope.slides.push({
htmlUrl: strTemplatePath,
id: intCurrentIndex++
});
}
And then use that in the template:
<div uib-slide ng-repeat="slide in slides track by slide.id" index="slide.id">
<div ng-include="slide.htmlUrl"></div>
</div>
Here's a somewhat working fiddle: jsfiddle.net, although I had to fill in a few blanks here and there.

why $scope change the value in the whole page?

I'm learning AngularJS and I'm trying to make a todo app.
Everything works great except that when I'm trying to add a new todo, the previous todos changing as well.
I think it's because the $scope changing its value in the whole page and I want to chnage it only in the last todo which just generated.
Maybe my code would be wrong for this purpose, again, I just started learning AngularJS.
Hope you can help me out, here is my code:
var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'pages/main.html',
controller: 'mainController'
})
.when('/todo', {
templateUrl: 'pages/todo.html',
controller: 'subController'
})
});
myApp.controller('mainController', ['$scope', function($scope){
}]);
myApp.controller('subController', ['$scope', '$compile', function($scope, $compile){
$scope.getMsg = function(){
$scope.todoHeader = $('#header').val();
$scope.todoMsg = $('#msg').val();
var item = $compile("<todo-item todo-Title='{{todoHeader}}' todo-message='{{ todoMsg }}'></todo-item>")($scope);
$(".list-group").append(item);
}
}]);
myApp.directive('todoItem', function(){
return {
templateUrl: 'directives/todoItem.html',
scope: {
todoTitle: "#",
todoMessage: "#"
}
};
});
<h3>Todo Page</h3>
<div style="margin:auto;margin-bottom: 10px;display:table;">
<input type="text" id="header" placeholder="Enter todo header" style="margin-right:10px;padding:5px;"><br>
<textarea type="text" id="msg" placeholder="Enter todo message" style="margin-right:10px;padding:5px;"></textarea><br>
<button type="button" class="btn btn-primary" ng-click="getMsg()">Add Todo</button>
</div>
<div class="list-group" style="margin: auto; display: table;">
</div>
Here is the directive (todoItem.html) code:
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start" style="width:600px">
<div class="d-flex w-100 justify-content-between">
<h1 class="mb-1">{{ todoTitle }}</h1>
</div>
<p class="mb-1">{{ todoMessage }}</p>
Yes indeed in your getMsg function you are always overriding the same $scope todoHeader and todoMessage variables .
And this is the default behaviour of a variable in the $scope, if a variable is declared in the $scope will be shared in the whole application, so it's changed it will affect all it's occurences in the pages.
Solution:
I think you should store your todos in an array in your scope and each time push a todo item into it, or just make the two todoHeader and todoMessage local to your getMsg function and use them in your new HTML todo item.
This is how would be your code:
//If you wanted to store the todos in an array
$scope.todos = [];
$scope.getMsg = function() {
var todoHeader = $('#header').val();
var todoMsg = $('#msg').val();
//or if you want to store the todos in an array
$scope.todos.push({
todoHeader: todoHeader,
todoMessage: todoMessage
});
var item = $compile("<todo-item todo-Title='+todoHeader+' todo-message='+todoMessage+'></todo-item>")($scope);
$(".list-group").append(item);
}

How to display a returned json in angular view?

I am implementing a search in the github repository.
I need to display the information that i get from here: https://api.github.com/search/repositories?q=bootstrap . for instance into a view or HTML
<div ng-app="newsearchApp">
<div ng-controller="MainCtrl">
<form action="#/about" method="get">
<input ng-model="searchText" />
<button ng-click="search()">Search</button>
</form>
</div>
</div>
the code for searching the Github repository;
angular.module('newsearchApp')
.controller("MainCtrl", ["$scope", function($scope) {
$scope.searchText = "";
$scope.search = function() {
console.log($scope.searchText);
var item = $scope.searchText;
// console.log(item)
var GithubSearcher = require('github-search-api');
var github = new GithubSearcher({username: 'test#something.com', password: 'passwordHere'});
var params = {
'term': $scope.searchText
};
//i am not certain about the 'userData'
github.searchRepos(params, function(data) {
console.log(data);
$scope.userData = data; //i am not certain about the 'repoData'
});
} }]);
the problem is here, when populating the json object to HTML
<div ng-repeat="repo in userData | filter:searchText | orderBy:predicate:reverse" class="list-group-item ">
<div class="row">
<div class="col-md-8">
<h4>
<small>
<span ng-if="repo.fork" class="octicon octicon-repo-forked"></span>
<span ng-if="!repo.fork" class="octicon octicon-repo"></span>
<small>{{repo.forks_count}}</small>
</small>
<a href="{{repo.html_url}}" target="_blank" >
{{repo.name}}
</a>
<small>{{repo.description}}</small>
<small>{{repo.stargazers_count}}</small>
<a href="{{repo.open_issues_count}}" target="_blank" >
Open Issues
</a>
<small>{{}}</small>
</h4>
</div>
</div>
</div>
the results are null on the HTML but are not null on the console.
thanks in advance
the results are null
The problem is, that Angular doesn't notice that the GitHub server has answered and doesn't update the view. You have to tell Angular manually to re-render the view. Try calling $scope.$apply():
github.searchRepos(params, function(data) {
console.log(data);
$scope.userData = data;
$scope.$apply();
});
If you'd make your request to the GitHub API with Angulars $http service, then this would not be needed - you'll only need $scope.$apply() if something asynchronous happens which doesnt live in the "Angular world" - for example things like setTimeout, jQuery ajax calls, and so on. That's why there are Angular wrappers like $timeout and $http.
More details: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
The GitHub API can be accessed using the AngularJS $http service:
app.controller("myVm", function($scope,$http) {
var vm = $scope;
var url = "https://api.github.com/search/repositories?q=bootstrap"
$http.get(url).then(function onSuccess(response) {
vm.data = response.data;
console.log(vm.data);
})
})
HTML
<div ng-app="myApp" ng-controller="myVm">
<div ng-repeat="item in data.items">
{{item.full_name}}
</div>
</div>
The DEMO on JSFiddle
Since you're not using the Angular $http service, angular is not aware of the changes. You need to manually tell Angular to re-render and evaluate by using
$scope.$apply();

Can Siblings Controllers communicate with each other without the help of the Parent - AngularJS

I'm working on a small app in AngularJS. My project contain a Body.html file that contain 3 views: SideMenu, Header and Content, each with each own Controller and a MainController as there parent - the controller of the Body.html.
Can the header's controller change a property in the side-menu - the open/close status of the side-menu.
And Can the side-menu controller change a property in the header - the header's text.
I can use the main controller, since both of the header's controller and the side-menu controller can reference the main controller. But the data won't be consist. Updating the data from the 1st controller wan't effect the data in the 2nd controller (without the use of $watch).
Can both the side-menu's controller and the header's controller (sibling controllers) communicate with each other? without the help of there parent?
Body.html
<div>
<!-- Header placeholder -->
<div ui-view="header"></div>
<!-- SideMenu placeholder -->
<div ui-view="sideMenu"></div>
<!-- Content placeholder -->
<div ui-view></div>
</div>
Header.html
<div>
{{ headerCtrl.text }}
</div>
<div ng-click="headerCtrl.openSideMenu()">
--Open--
</div>
HeaderController.js
// sideMenuCtrl = ???
headerCtrl.text = "Title";
headerCtrl.openSideMenu = function()
{
sideMenuCtrl.isSideMenuOpen = true;
};
SideMenu.html
<div ng-class={ 'side-menu-open': sideMenuCtrl.isSideMenuOpen }>
<div ng-repeat="menuItem in sideMenuCtrl.sideMenuItems"
ng-click="sideMenuCtrl.selectMenuItem(menuItem)">
{{ menuItem.text }}
</div>
</div>
SideMenuController.js
// headerCtrl = ???
sideMenuCtrl.selectMenuItem = function(menuItem)
{
headerCtrl.text = menuItem.text;
}
As stated in my comment, you can use an AngularJS service to share some data between your controllers.
app.service('AppContextService', function(){
this.context = {
isSideMenuOpen: false
};
});
app.controller('SideMenuCtrl', ['$scope', 'AppContextService', function($scope, AppContextService) {
// exposing the application context object to the controller.
$scope.appContext = AppContextService.context;
}]);
app.controller('HeaderCtrl', ['$scope', 'AppContextService', function($scope, AppContextService) {
$scope.appContext = AppContextService.context;
$scope.openSideMenu = function()
{
$scope.appContext.isSideMenuOpen = true;
};
}]);
Then adapt the HTML to use your shared appContext object.
<div ng-class={ 'side-menu-open': appContext.isSideMenuOpen }>
[...]
</div>
Here is a working fiddle that illustrates the issue: fiddle
This answer covers the use of a service to fit your needs but I am sure that there are other (and perhaps better) ways to tackle the problem which might involve other Angular feature, or even some overall application refactoring.
To dig a little deeper, this SO topic might be a good start: difference between service, factory and providers

Import same information to modal

It's an ad (discount codes for e-shops) app I'm trying to make.
Ads are listed in to Array , each ad having 4 things (name, image link , discount (%) , discount code)
This is how I list the ads (ng-repeat is used) :
<div class="list">
<div class="item item-thumbnail-left" href="#" ng-repeat="item in dovanosListArray" >
<img ng-src={{item.image}}>
<h2>{{item.name}}</h2>
<button menu-toggle="right"class="button-icon icon ion-ios7-arrow-forward" ng-click="modal.show()"></button>
<p>Nuolaida : {{item.discount}} %</p>
</div>
</div>
So when you click the one you want, modal opens. In the modal , I need to show the same {{item.name}} again and give it's {{item.discountcode}}. How am i supposed to do this ? I can't use ng-repeat because there are other items in the same array as well.
Sorry for my English, I think that you need is something like this:
var modalInstance = $modal.open({
templateUrl: 'Modal.html',
controller: 'ModalCtrl',
resolve: {
item: function () {
return item;
}
}
And in you controller:
angular.controller('ModalCtrl', ['$scope','item',
function($scope, item , ) {
$scope.item=tem;
..........................
}])
So in your controller you already hace the value of item;
Pass the item as an object parameter in your modal.show() function.

Categories

Resources