Is it possible to transclude the tab content? - angular-ui-bootstrap

Is it possible to create a tab with either HTML content or move the element directly to the content?
Here is what I am trying to do, ultimately, i want to just move existing element(s) inside the tab content:
HTML
<body ng-controller="MainCtrl">
<div class="container">
<tabset ui-sortable="sortableOptions" ng-model="tabs">
<tab class="tab" ng-repeat="tab in tabs" sortable-tab heading="{{tab.title}}">{{tab.content}}</tab>
</tabset>
<button type="button" ng-click="addSimple()">Add simple</button>
<button type="button" ng-click="addHtml()">Add html</button>
<button type="button" ng-click="addElement()">Add element</button>
<button type="button" ng-click="removeTab()">Remove tab</button>
</div>
</body>
JS
var app = angular.module('plunker', ['ui.bootstrap', 'ui.sortable']);
app.controller('MainCtrl', function($scope) {
var count = 0;
$scope.sortableOptions = {
distance: 10,
axis: 'x',
update: function(event, ui) {
// $scope.activeTab = ui.item.sortable.dropindex;
}
};
$scope.tabs = [
{title:'Test', content:'hello world'},
];
$scope.addSimple = function() {
count++;
var newTab = {title: 'New tab ' + count, content: 'Works'};
$scope.tabs.push(newTab);
}
$scope.addHtml = function() {
count++;
var newTab = {title: 'New tab ' + count, content: '<div>Broken</div>'};
$scope.tabs.push(newTab);
}
$scope.addElement = function() {
count++;
var newTab = {title: 'New tab ' + count, content: angular.element('<div>Broken</div>')};
$scope.tabs.push(newTab);
}
$scope.removeTab = function() {
$scope.tabs.pop();
}
});
Plunkr

It's already transcluded, but if you want to inject HTML, you'll have to use ngBindHtml (requires ngSanitize as a dependency).
Updated Plunker
Add angular-sanitize.js make sure ngSanitize is added as a dependency:
var app = angular.module('plunker', ['ui.bootstrap', 'ui.sortable', 'ngSanitize']);
Change your markup to add ng-bind-html:
<tab class="tab" ng-repeat="tab in tabs" sortable-tab heading="{{tab.title}}">
<div ng-bind-html="tab.content"></div>
</tab>
Then you can pass html directly:
{title: 'New tab ' + count, content: '<strong>Works with <span class="red">ngBindHtml</span></strong>'}
Or, using the angular.element html() method to grab the element object's html:
{title: 'New tab ' + count, content: angular.element('<div>Broken</div>').html()}

Related

Jquery UI selectable: Define multiple selectable objects DYNAMICALLY

I really need some help on the following: I am currently developing a shopping cart. Whenever a new product is appended to shopping cart it becomes a button. This button (product) is used to add some modifiers to each product. The button definition can be seen below:
var productAdded = $('<tr class="product" data-real_id = "'+ id +'" data-id_modal="'+ mod_id +'"><td class="product_name2"><button href="#0" class="button2" style="background-color:#00a65a;" data-comment="" data-modifiers="" data-span_mod = "" data-real_id = "'+ id +'" data-id_modall="'+ mod_id +'" id = "'+ comment_id +'">' + product_name + '</button></td><td class="quantity"><span class="select"><select id="cd-product-'+ id +'" name="quantity"><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option></select></span></td><td class="price">' + product_price + '</td><td><i class="fa fa-trash-o fa-2x" aria-hidden="true"></i></td></tr>');
Whenever each of the product's button is pressed a JQUERY UI dialog window is opened whic contains a JQUERY UI SELECTABLE object:
<div class="modal fade" id="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"></div>
<div class="modal-body" style="margin-top:5px;">
<div style="width:100%; float:left;">
<label for="modifier">Τροποποιητές: </label>
<span id="select-result" data-modifiers_span=""></span>
<ol id="selectable" class="txt-modifiers">
<!-- INSERTED BY JQUERY DYNAMICALLY PER PRODUCT -->
</ol>
</div>
<label for="comment">Σχόλιο: </label>
<textarea rows="4" cols="50" name="comment" id="comment" value="" class="form-control txt-comment" style="vertical-align: top;"></textarea>
</div>
<div class="modal-footer" style="margin-top:10px;">
<button class="btn btn-success btn-save" data-id="" data-id_modall="">Αποθήκευση</button>
<button class="btn btn-default" data-dismiss="modal">Κλείσιμο</button>
</div>
</div>
</div>
</div>
As you can see below the modifiers of the product are extracted using AJAZ+PHP from mysql database:
$(document).on('click touchstart','.button2',function(e){
e.preventDefault();
var id = $(this).attr('id'); //Get element id
var real_id = $(this).attr('data-real_id');
var comment = $(this).attr('data-comment'); //Get comment
var modifiers = $(this).attr('data-modifiers'); //Get modifiers
var teeee = $(this).attr('data-id_modall');
$('#modal .txt-comment').val(comment);
$('#modal .btn-save').attr('data-id',id);
$('#modal .btn-save').attr('data-id_modall',teeee);
//alert(modifiers);
if (modifiers.length == 0)
{
$("#selectable").html('<img src="images/ajax-loader.gif" />');
var request = $.ajax({
url: 'http://127.0.0.1:8080/Food%20Ball/backup/FoodBall%20Site%20form_dt_2/Food%20Ball%20Site/get_item_modifiers.php?item_id=' + real_id,
cache: false,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
type: 'get',
success: function(data) {
if( data.result != 'Not'){
$("#selectable").html(data.options);
$('#modal .txt-modifiers').val(data.options);
}
else{ $("#selectable").html('Δεν υπάρχουν!');
$('#modal .txt-modifiers').val('Δεν υπάρχουν!'); }
}
});
}
else { $('#modal .txt-modifiers').val(modifiers); $("#selectable").html(modifiers);}
$('#modal').dialog('open');
});
And the selectable object:
$(function () {
$('#selectable').on('touchstart mousedown', function(e) {e.metaKey = true;})
.selectable({
selected: function(event, ui) {
var result = $( "#select-result").empty();
$( ".ui-selected", this ).each(function() {
result.append($(this).attr('data-product_modifier') + ', ');
});
},
unselected: function(event, ui){
var result = $( "#select-result");
$( ".ui-unselected", this ).each(function() {
result.remove($(this).attr('data-product_modifier') + ', ');
});
}
});
});
And finally the "Save" button for each dialog modal window:
$(document).on('click touchstart','.btn-save',function(e){
e.preventDefault();
var id =$(this).attr('data-id'); //Get data id
var comment =$('.txt-comment').val(); //get the comment
var modifiers =$('.txt-modifiers').val(); //get the modifier
//update the "order" note column modal
var note_modal = '#' + $(this).attr('data-id_modall'); //get the id row of the order modal
var note_modal2 = '#2' + $(this).attr('data-id_modall'); //get the id row of the order modal
$(note_modal).find('#note_modal').text(comment+'--'+modifiers);
$(note_modal2).find('#note_modal2').text(comment+'--'+modifiers);
$('#'+id).attr('data-comment',comment);
$('#'+id).attr('data-modifiers',modifiers);
//Save it in data base..s
$('#modal').dialog('close');
$('.txt-comment').val('');//clear text area
$('.txt-modfiers').val('');//clear text area
});
$(document).on('click','.btn-default',function(e){
e.preventDefault();
//Save it in data base..s
$('#modal').dialog('close');
$('.txt-comment').val('');//clear text area
$('.txt-modfiers').val('');//clear text area
});
My problem is that if i add more than one products to my cart the selected modifiers appear for all products. How can i have multiple selectable objects defined dynamically and save each product's selected modifiers?
If anyone can help on this i will really appreciate it
Thank you
ok solved it:
simply put the following code within the successful return of the Ajax call:
var request = $.ajax({
url: 'http://127.0.0.1:8080/Food%20Ball/backup/FoodBall%20Site%20form_dt_2/Food%20Ball%20Site/get_item_modifiers.php?item_id=' + real_id,
cache: false,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
type: 'get',
success: function(data) {
if( data.result != 'Not'){
$("#selectable").html(data.options);
$('#modal .txt-modifiers').val(data.options);
$( "#selectable" ).selectable({
stop: function() {
result_mod = $( ".select_result" ).empty();
$( ".ui-selected", this ).each(function() {
result_mod.append(' +' + $(this).attr('data-product_modifier'));
//array_mod = array_mod + (' +' + $(this).attr('data-product_modifier'));
$('#modal .select_result').val(result_mod);
});
}
});
}
else{ $("#selectable").html('Δεν υπάρχουν!');
$('#modal .txt-modifiers').val('Δεν υπάρχουν!');
$( ".select_result").html('');
$('#modal .select_result').val('');
}
}
});

Tabs in dialog box jquery

I would like to get tabs in a dialog box. Here's the code :
HTML :
<div id="box_form1">
<div id="dialog" title="Tab data">
<form>
<fieldset class="ui-helper-reset">
<label for="tab_title">Title</label>
<input type="text" name="tab_title" id="tab_title" value="Tab Title" class="ui-widget-content ui-corner-all">
<label for="tab_content">Content</label>
<textarea name="tab_content" id="tab_content" class="ui-widget-content ui-corner-all">Tab content</textarea>
</fieldset>
</form>
</div>
<button id="add_tab">Add Tab</button>
<div id="tabs">
<ul>
<li>TOTAL <span class="ui-icon ui-icon-close" role="presentation">Remove Tab</span></li>
</ul>
<div id="tabs-1">
<table>
<thead>
<tr>
<th>title</th>
<th>2015</th>
</tr>
</thead>
<tbody>
<tr>
<td>INV</td>
<td>1000</td>
</tr>
</tbody>
</table>
</div>
</div>
JAVASCRIPT :
$(document).ready(function () {
$('#box_form1').dialog({
title: "test",
autoOpen: false,
height: 600,
width: 600,
modal: true,
});
$('#module_ppi').button().click(function (e) {
$('#box_form1').dialog('open');
});
var tabTitle = $("#tab_title"),
tabContent = $("#tab_content"),
tabTemplate = "<li><a href='#{href}'>#{label}</a> <span class='ui-icon ui-icon-close' role='presentation'>Remove Tab</span></li>",
tabCounter = 2;
var tabs = $("#tabs").tabs();
// modal dialog init: custom buttons and a "close" callback resetting the form inside
var dialog = $("#dialog").dialog({
autoOpen: false,
modal: true,
buttons: {
Add: function () {
addTab();
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
},
close: function () {
form[0].reset();
}
});
// addTab form: calls addTab function on submit and closes the dialog
var form = dialog.find("form").submit(function (event) {
addTab();
dialog.dialog("close");
event.preventDefault();
});
// actual addTab function: adds new tab using the input from the form above
function addTab() {
var label = tabTitle.val() || "Tab " + tabCounter,
id = "tabs-" + tabCounter,
li = $(tabTemplate.replace(/#\{href\}/g, "#" + id).replace(/#\{label\}/g, label)),
tabContentHtml = tabContent.val() || "Tab " + tabCounter + " content.";
tabs.find(".ui-tabs-nav").append(li);
tabs.append("<div id='" + id + "'><p>" + tabContentHtml + "</p></div>");
tabs.tabs("refresh");
tabCounter++;
}
// addTab button: just opens the dialog
$("#add_tab")
.button()
.click(function () {
dialog.dialog("open");
});
// close icon: removing the tab on click
tabs.delegate("span.ui-icon-close", "click", function () {
var panelId = $(this).closest("li").remove().attr("aria-controls");
$("#" + panelId).remove();
tabs.tabs("refresh");
});
tabs.bind("keyup", function (event) {
if (event.altKey && event.keyCode === $.ui.keyCode.BACKSPACE) {
var panelId = tabs.find(".ui-tabs-active").remove().attr("aria-controls");
$("#" + panelId).remove();
tabs.tabs("refresh");
}
});
});
http://jsfiddle.net/y25zw254/1/
The problem is : when I add a tab, the content of all tabs display.
How can I fix it ?
Thanks
You can have a look at this solution
$(document).ready(function() {
$("div#tabs").tabs();
$("button#add-tab").click(function() {
var num_tabs = $("div#tabs ul li").length + 1;
$("div#tabs ul").append(
"<li><a href='#tab" + num_tabs + "'>#" + num_tabs + "</a></li>"
);
$("div#tabs").append(
"<div id='tab" + num_tabs + "'>#" + num_tabs + "</div>"
);
$("div#tabs").tabs("refresh");
});
});
http://jsfiddle.net/axrwkr/ujUu2/
In this I am adding a tab on click of a button you can extend that inside your dialog box.

give default value to md-autocomplete

How to pass default value in md-autocomplete?
Image 1 : HTML code
Image 2 : JS code
Image 3 : Output
As you can see, I am not getting any default country as output. Is there any way to do that?
Assign yr SearchText the default value & selectedItem the object.
$scope.local ={
...
searchText : 'Default Value',
selectedItem : 'Default object'
...
}
I write small codepen with autocomplete and default value.
What you must do:
Init main model.
Define model field, used in autocomplete md-selected-item property.
Define callback for loading autocomplete items.
Before save main model extract id (or other field) from associated field.
Main error in your code here:
$scope.local = {
...
selectedItem: 1, // Must be object, but not integer
...
}
(function(A) {
"use strict";
var app = A.module('app', ['ngMaterial']);
function main(
$q,
$scope,
$timeout
) {
$timeout(function() {
$scope.user = {
firstname: "Maxim",
lastname: "Dunaevsky",
group: {
id: 1,
title: "Administrator"
}
};
}, 500);
$scope.loadGroups = function(filterText) {
var d = $q.defer(),
allItems = [{
id: 1,
title: 'Administrator'
}, {
id: 2,
title: 'Manager'
}, {
id: 3,
title: 'Moderator'
}, {
id: 4,
title: 'VIP-User'
}, {
id: 5,
title: 'Standard user'
}];
$timeout(function() {
var items = [];
A.forEach(allItems, function(item) {
if (item.title.indexOf(filterText) > -1) {
items.push(item);
}
});
d.resolve(items);
}, 1000);
return d.promise;
};
}
main.$inject = [
'$q',
'$scope',
'$timeout'
];
app.controller('Main', main);
}(this.angular));
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-aria.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-animate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.js"></script>
</head>
<body ng-app="app" flex layout="column" layout-margin ng-controller="Main">
<md-content layout="column" class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Form</h3>
</div>
</md-toolbar>
<md-content class="md-whiteframe-z1">
<div class="md-padding">
<md-input-container>
<label for="firstname">First name</label>
<input type="text" name="firstname" ng-model="user.firstname" />
</md-input-container>
<md-input-container>
<label for="lastname">Last name</label>
<input type="text" name="lastname" ng-model="user.lastname" />
</md-input-container>
<md-autocomplete md-selected-item="user.group" md-items="item in loadGroups(filterText)" md-item-text="item.title" md-search-text="filterText">
<md-item-template>{{ item.title }}</md-item-template>
<md-not-found>No items.</md-not-found>
</md-autocomplete>
</div>
</md-content>
</md-content>
<md-content class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Model as JSON</h3>
</div>
</md-toolbar>
<md-content class="md-padding">
<p>
{{ user | json }}
</p>
</md-content>
</md-content>
</body>
I know this is an old question, but some people may benefit from my solution. I struggled with the problem of the model for the auto-complete being asynchronous and having my autocompletes as part of an ng-repeat. Many of the solutions to this problem found on the web have only a single auto complete and static data.
My solution was to add another directive to the autocomplete with a watch on the variable that I want to set as default for the auto complete.
in my template:
<md-autocomplete initscope='{{quote["Scope"+i]}}' ng-repeat='i in [1,2,3,4,5,6,7,8]'
class='m-1'
md-selected-item="ScopeSelected"
md-clear-button="true"
md-dropdown-position="top"
md-search-text="pScopeSearch"
md-selected-item-change='selectPScope(item.label,i)'
md-items="item in scopePSearch(pScopeSearch,i)"
md-item-text="item.label"
placeholder="Plowing Scope {{i}}"
md-min-length="3"
md-menu-class="autocomplete-custom-template"
>
then in my module:
Details.directive('initscope', function () {
return function (scope, element, attrs) {
scope.$watch(function (){
return attrs.initscope;
}, function (value, oldValue) {
//console.log(attrs.initscope)
if(oldValue=="" && value!="" && !scope.initialized){
//console.log(attrs.initscope);
var item = {id:0, order:0,label:attrs.initscope?attrs.initscope:"" }
scope.ScopeSelected = item;
scope.initialized = true;
}
});
};
});
this checks for changes to the quote["Scope"+i] (because initially it would be null) and creates an initial selected item and sets the autocompletes' selected item to that object. Then it sets an initialized value to true so that this never happens again.
I used timeout to do this.
$timeout(function() {
$scope.local = {selectedItem : 1}
}, 2000);

JQuery UI highlight effect color parameter ignored in Knockout foreach

Im trying to apply the JQuery UI highlight effect to an element when an item that is bound to a knockout observablearray is updated.
The highlight effect is applied but the highlight color used is always the elements current background color. even if I specify the highlight color using the { color: 'XXXXXXX' } option.
any ideas what might be happening?
Thanks,
Steve.
Code below: The element is the span.tag
<div class="row">
<div class="span12">
<div class="tagsinput favs span12" style="height: 100%;" data-bind="foreach: favs, visible: favs().length > 0">
<span class="tag" data-bind="css: $root.selectedFav() == userPrefID() ? 'selected-fav' : '', attr: { id: 'fav_' + userPrefID() }">
<span data-bind="text: name, click: $root.loadFav.bind($data)"></span>
<a class="tagsinput-fav-link"><i class="icon-trash" data-bind="click: $root.delFav.bind($data)"></i></a>
<a class="tagsinput-fav-link-two" data-bind="visible: $root.selectedFav() == userPrefID()"><i class="icon-save" data-bind=" click: $root.saveFav.bind($data)""></i></a>
</span>
</div>
</div>
</div>
// This is the code that does a save via ajax then highlights the element when done.
$.getJSON('#Url.Action("SaveFav","User")', { id: item.userPrefID(), fav: window.JSON.stringify(fav) }, function (result) {
var savedFav = ko.utils.arrayFirst(self.favs(), function (aFav) {
return aFav.userPrefID() == result.userPrefID; // <-- is this the desired fav?
});
// Fav found?
if (savedFav) {
// Update the fav!
savedFav.value(result.value);
}
}).done(function () {
var elementID = "#fav_" + item.userPrefID();
highlightElement(elementID);
});
// Function to highlight the element
function highlightElement(element) {
$(element).effect("highlight", {}, 1500);
}
I would do this the 'knockout' way... use a custom bindingHandler. You shouldn't be directly manipulating DOM in your viewModel, but only touching properties of your viewModel.
Taking this approach, you simply set a boolean value to true when your save is complete... this triggers the highlight effect (the jquery/dom manipulation neatly hidden away from your viewmodel) and when highlight effect completes, the handler sets the boolean back to false. Nice and tidy.
HTML:
<div id="#fav" data-bind="highlight: done">This is a test div</div>
<br />
<button data-bind="click: save">Simulate Save</button>
Javascript:
ko.bindingHandlers.highlight = {
update: function(element, valueAccessor) {
var obs = valueAccessor();
var val = ko.unwrap(obs);
if (val) {
$(element).effect("highlight", {}, 1500, function() {
obs(false);
});
}
}
};
var vm = function() {
var self = this;
self.done = ko.observable(false);
self.save = function() {
self.done(true);
};
}
ko.applyBindings(new vm());
Fiddle:
http://jsfiddle.net/brettwgreen/pd14q4f5/

knockout.js, jquery-ui, button click and param

I'm using jQuery UI to create a "button" to a given html element. I'm using Knockout.js to generate the html element (foreach).
However, I can't find the way how to pass a parameter to the click event for knockout.js generated items. In the following example, the somewhat static sampleButton works, but not the itemButton items.
http://jsfiddle.net/patware/QVeVH/
function ViewModel() {
var self = this;
self.ping = 'pong';
self.items = ko.observableArray([
{ display: 'Cars', id: 1 },
{ display: 'Fruits', id: 2 },
{ display: 'Humans', id: 3 },
{ display: 'Software', id: 4 },
{ display: 'Movies', id: 5 },
]);
}
ko.applyBindings(new ViewModel());
$("#sampleButton").button().data('someData',101);
$("#sampleButton").click(function(e){
alert('clicked sample: [' + $(this).data('someData') + ']');
});
$(".itemButton").button().data('someData',$(this).id);
$(".itemButton").click(function(){
alert('clicked item: [' + $(this).attr('foo') + ']');
});
ping-<span data-bind="text: ping"></span>
<div id="sample">
<div id="sampleButton">
<h3>Sample Button</h3>
Click here too
</div>
</div>
<div data-bind="foreach: items">
<div class="itemButton" data-bind="foo: id">
<h3 data-bind="text:display"></h3>
</div>
</div>​
Consider using ko.dataFor instead of applying data with jquery.
Working sample based on your example http://jsfiddle.net/QVeVH/6/
You can set everything up using a custom binding.
http://jsfiddle.net/jearles/QVeVH/7/

Resources