Related
I am struggling to understand this.
I have a dictionary titled alldicts that I am passing from Views in Django into the HTML. How do I then reference that dictionary to Jquery to autofill in input values in my HTML?
My code in Views.Py:
mydict1 = {
'one' : 1
'two' : 2
'three' : 3
}
mydict2 = {
'one' : 4
'two' : 5
'three' : 6
}
mydict3 = {
'one' : 7
'two' : 8
'three' : 9
}
alldicts={
'mydict1': mydict1,
'mydict2': mydict2,
'mydict3': mydict3
}
return render(request, self.template_name, alldicts)
In the HTML section of my code, I have a select dropdown with the options "mydict1","mydict2", and "mydict3". Below it I have three inputs (number of inputs will be dynamic, but wanted to give a simple example) that I want to auto fill to match the selected option. (IE if I select mydict2 in the dropdown, the inputs (#one, #two, and #three) will fill to be 4,5, and 6 respectively).
In html, if I try something like this, it doesn't work:
$("#hselect").change(function() {
var a = "{{alldicts}}";
var selectedValue = $(this).val();
$.each( a, function(idx, obj) {
$.each( obj, function(key, value){
if (selectedValue == idx) {
$('#'+key).val(value);
}
});
});
}
<select id = "hselect" name="hselect" style="width: 250px;" onchange="changeoption();">
<option> mydict1 </option>
<option> mydict2 </option>
<option> mydict3 </option>
</select>
<input id='one' ><br>
<input id='two' ><br>
<input id='three' ><br>
This does not work. However if I pass the dictionary statically through the HTML, it does work. How do I pass dynamically from Views?
For example this does work:
$("#hselect").change(function() {
var a = {
'mydict1' = {'one' : 1, 'two' : 2, 'three' : 3},
'mydict2' = {'one' : 4, 'two' : 5, 'three' : 6},
'mydict3' = {'one' : 7, 'two' : 8, 'three' : 9},
};
var selectedValue = $(this).val();
$.each( a, function(idx, obj) {
$.each( obj, function(key, value){
if (selectedValue == idx) {
$('#'+key).val(value);
}
});
});
}
<select id = "hselect" name="hselect" style="width: 250px;" onchange="changeoption();">
<option> mydict1 </option>
<option> mydict2 </option>
<option> mydict3 </option>
</select>
<input id='one' ><br>
<input id='two' ><br>
<input id='three' ><br>
The only thing that changes is how I pass the dictionary, mydicts, and define the variable a. How do I do this dynamically from Views.Py?
You need ensure convert all datatype in alldicts from python object to string or number.
Change alldicts in your views.py from python dict to json format:
import json
json_alldicts = json.dumps(alldicts)
For jinja template
var a = JSON.parse('{{ json_alldicts | tojson | safe }}');
console.log(a);
For django template
var a = JSON.parse('{{ json_alldicts | safe }}');
console.log(a);
The answer is quite tricky (updated my Answer)
Now its working dynamically.
HTML
<div id="container"></div>
<div id="inputs"></div>
This is are your objects (console.log helps):
Four dynamic I added a fourth element to the first mydict1
mydict1 = {
'one': 1,
'two': 2,
'three': 3,
'four': 4
}
mydict2 = {
'one': 4,
'two': 5,
'three': 6
}
mydict3 = {
'one': 7,
'two': 8,
'three': 9
}
alldicts = {
'mydict1': mydict1,
'mydict2': mydict2,
'mydict3': mydict3
}
console.log('alldicts', alldicts);
These creates the dynamic select option box:
var markup = '';
markup += '<select id="hselect" name="hselect" style="width: 250px;">';
$.each(alldicts, function(idx, obj) {
console.log('obj', idx);
markup += '<option value="' + idx + '">' + idx + '</option>';
});
markup += '</select>';
$("#container").append(markup);
This is the changeHandler for changing the select options
var markupInputs = '';
$('#hselect').on('change', function() {
$('#inputs').empty();
console.log(this.value);
var option = this.value;
var elements = {};
$.each(alldicts, function(idx, obj) {
console.log('idx', idx)
if (idx == option) {
$.each(obj, function(idx1, obj1) {
elements[idx1] = obj1;
});
}
});
console.log('arr2', elements);
$.each(elements, function(index, value) {
markupInputs += '<input id="' + index + '" value="' + value + '"></input><br>';
});
$("#inputs").append(markupInputs);
markupInputs = '';
});
<style>
#editor-container {
height: 375px;
}
.link {
color:blue;
}
</style>
<div id="editor-container">
This is a test
</div>
<script type="text/javascript">
var quill = new Quill('#editor-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block']
]
},
placeholder: 'Compose an epic...',
theme: 'bubble' // or 'bubble'
});
quill.clipboard.dangerouslyPasteHTML(5, "<span class=\"link\" data-test=\"test\">testing</span>", "silent");
</script>
MVCE - https://codepen.io/anon/pen/QMQMee
The HTML get stripped out despite being pretty harmless (this will be handled better later).
My current plan, due to the way Quill does not allow pasted html, is (As part of a click action on the mentioned person's name):
$("#tag-selectable-users-list li").on("click",
function() {
var $this = $(this);
var startIndex = $this.data("data-start-index");
var userName = $this.data("data-user-name");
var userId = $this.data("data-user-id");
var taggedUserIds = $("#hiddenTaggedUsers");
taggedUserIds.val((taggedUserIds.val()||"") + ";" + userId);
var delta = [];
if (startIndex > 0) {
//retain up to the tag start
delta.push({ retain: parseInt(startIndex) });
}
//delete the junk
delta.push({ delete: tagStatus.Total.length });
//insert the new characters
delta.push({
insert: "##" + userName,
attributes: {
color: "blue",
underline: "true"
}
});
//insert a blank space to end the span
delta.push({ insert: " " });
quill.updateContents(delta,
'api');
});
}
I have this directive that brings sub-categories by the categoryId in this application the categories are called services and the sub-categories are called services-child( just for you to know ).
ok
The File that contain the directive service-detail.php has:
<services-child serviceid="{{id}}"></services-child>
The directive :
'use strict';
app.directive('servicesChild', function ($window,$state,servChildService) {
return {
require: '^form',
restrict: 'EA',
scope: {
serviceid: '#',
},
templateUrl:'assets/views/partials/service-child.php',
link: function ($scope, $element, $attributes) {
var serviceId = $attributes.serviceid;
$scope.childs = servChildService;
servChildService.loadServiceChilds(serviceId);
$scope.serviceChilds = servChildService.serviceCH;
}
};
});
app.factory('serviceChildResource', ['$resource', function($resource) {
return $resource("/services/serviceChild/:id", {id: '#id'}, {
getChilds: {
method: 'GET'
}
});
}]);
app.service('servChildService', function(serviceChildResource) {
var self = {
'isLoading': false,
'showBlock': true,
'serviceCH': [],
'loadServiceChilds': function(serviceId){
if (!self.isLoading) {
self.isLoading = true;
var params = {
'id': serviceId,
};
self.serviceCH = [];
serviceChildResource.getChilds(params, function(data){
if(data.childs.length > 0){
angular.forEach(data.childs, function(value, key){
self.serviceCH.push(new serviceChildResource(value));
self.isLoading = false;
self.showBlock = true;
});
}else{
self.showBlock = false;
self.isLoading = false; //show the loading.
}
});
}
}
};
return self;
});
Now the services-child view is this service-child.php:
<div class="panel panel-white" ng-show="childs.showBlock">
<div class="panel-heading border-light">
<h4 class="panel-title"><span class="text-bold">Add More Services</span>
</h4>
</div>
<div class="table-responsive">
<table class="table table-bordered table-hover" id="sample-table-1">
<thead>
<tr>
<th>Service</th>
<th>Description</th>
<th>Price</th>
<th>Qty.</th>
<th>Select</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="service in serviceChilds">
<td>{{service.name}}</td>
<td ng-bind-html="service.description">
{{service.description}}
</td>
<td>${{service.price}}</td>
<td>
<qty-select ng-hide="{{service.single_service}}"
price="{{service.price}}"
id="{{service.id}}"
indexid = {{$index}}>
</qty-select>
</td>
<td><input type="checkbox" value="{{service.id}}"
ng-model="$root.servCheck[service.id]"
name="servCheckN"/></td>
</tr>
</tbody>
</table>
<div ng-show="childs.isLoading">
<span us-spinner="{radius:10, width:5, length:4, lines:8}"></span>
</div>
</div>
</div>
Ok Now in this directive I have another Directive that has the Dynamic DropDown:
as you see this is the directive:
<qty-select ng-hide="{{service.single_service}}"
price="{{service.price}}"
id="{{service.id}}"
indexid = {{$index}}>
</qty-select>
Now this directive code is this qty-select.js:
'use strict';
app.directive('qtySelect', function ($window,$state,servChildService,$localStorage,$rootScope,$timeout) {
return {
require: '^form',
restrict: 'EA',
scope: {
indexid: '#',
},
templateUrl:'assets/views/partials/qty-select.php',
link: function ($scope, $element, $attributes) {
var i = 1;
while (i < 16) {
$scope.selectObj.push({'value' : $attributes.price * i,
'label' : i + ' (' + $attributes.price * i + ')',
'price' : $attributes.price * i,
'qty' : i,
});
i += 1;
};
console.log($rootScope.priceQty);
}
};
});
So basically what this directive does is creating a select option element
but it shows the price multiply by the index Ex. 1($10) which increment one by one
Ex. 2($20) so the result is something like this: if you pass 10 to the directive in the price attribute it will show:
<select ng-init="$parent.priceQty[indexid] = selectObj[0]"
ng-model="$parent.priceQty[indexid]" ng-change="updatePrice()"
ng-options="option.label for option in selectObj"
class="ng-valid ng-not-empty ng-dirty ng-valid-parse ng-touched" style="">
<option value="?"></option>
<option label="1 (15)" value="object:77">1 (15)</option>
<option label="2 (30)" value="object:78">2 (30)</option>
<option label="3 (45)" value="object:79">3 (45)</option>
<option label="4 (60)" value="object:80">4 (60)</option>
<option label="5 (75)" value="object:81">5 (75)</option>
<option label="6 (90)" value="object:82">6 (90)</option>
<option label="7 (105)" value="object:83">7 (105)</option>
<option label="8 (120)" value="object:84">8 (120)</option>
<option label="9 (135)" value="object:85">9 (135)</option>
</select>
Now this all works fine but I don't know how to get ride of the first empty option that angular append to the dropDown.
This is the View directive for select qty-select.php
<select ng-init="$root.priceQty[indexid] = selectObj[0]"
ng-model="$root.priceQty[indexid]" ng-change="updatePrice()"
ng-options="option.label for option in selectObj" >
</select>
<!-- <select ng-model="$root.priceQty[indexid]" ng-change="updatePrice(indexid)">
<option ng-repeat="value in selectObj" value="{{value.value}}"
ng-selected="$index == 1">{{value.label}}</option>
</select> -->
As you see in the I am trying with ng-repeat and with ng-options but
i am having problems with both.
Now if I work with $scope it works but when I am trying to use root
it does not work.
I notice that in my view select i have set
<select ng-init="$root.priceQty[indexid] = selectObj[0]"
but in the html that gets populated I see
<select ng-init="$parent.priceQty[indexid] = selectObj[0]"
$parent why ? is changing it.
and I need to set these input in the rootScope because I have to submit the form and I can no access to those values if I don't set the ng-model to be sent to the rootScope.
Also I tried to do this in the qty-select.js directive
after I build the select element i added this:
$scope.priceQty = $scope.selectObj[0];
and it worked but when I use $rooScope it doesn't work it says undefined.
$rootScope.priceQty = $scope.selectObj[0];
Any Idea?
Thank you
Hi thank you very much for your feedback...
Im not using $rootScope and a fixed the problem with the empty.
I had a lot architectural mistakes and thank you for your recommendations.
I totally change the way of using the directive.
Ok the way I solved the empty option was
'use strict';
app.directive('qtySelect', function ($window,$state,servChildService,$timeout,cartService,$cookies,$rootScope) {
return {
require: '^form',
restrict: 'EA',
scope: {
indexid: '#',
serviId: '#id',
servobj: '=',
},
templateUrl:'assets/views/partials/qty-select.php',
link: function ($scope, $element, $attributes) {
var i = 1;
var index = 0;
$scope.selectObj = [];
$scope.cartArray = [];
while (i < 16) {
$scope.selectObj.push({'value' : $attributes.price * i, //the value of the option tag (obligatory)
'label' : i + ' (' + $attributes.price * i + ')', //the copy (obligatory)
'price' : $attributes.price * i,
'qty' : i,
'serviceId' : $attributes.id,
'index' : index,
});
i += 1;
index += 1;
};
$timeout(function() {
document.getElementById("qty-"+$scope.indexid)[1].selected = true
//add the attribute ng-checked to filter them later.
document.getElementById("qty-"+$scope.indexid)[1].setAttribute("selected", 'selected');
}, 10);
}
};
});
I'm targeting the element by id and I am adding timeout because
the first load return undefined it seems the DOM is not ready
at that point so adding a timeout it give it enough time to the DOM to be ready.
Also I am adding the attribute selected="selected" manually since the selected true does not add the attribute selected and I need it to select later the whole element.
$timeout(function() {
document.getElementById("qty-"+$scope.indexid)[1].selected = true
//addinf manyally the attribute selected
document.getElementById("qty-"+$scope.indexid)[1].setAttribute("selected", 'selected');
}, 10);
Thank you
If you have recommendations are welcome.
This is the html directive:
<select ng-model="priceQty" ng-change="updatePrice(indexid,serviId,this)"
name="priceQty" id="qty-{{indexid}}">
<option ng-repeat="(key, value) in selectObj" value="{{value.price}}"
qty="{{$index+1}}" service-id="{{serviId}}">
{{$index+1}} ({{value.price}})
</option>
</select>
I am trying to make a simple dropdown using angularjs and want to invoke a function when the dropdown value is changed. Only when the dropdown selection is 'A', i want to display some other elements(say 'hello') in my page.
Here is the jsfiddle http://jsfiddle.net/gkJve/932/.
Html
<div ng-controller="Ctrl">
<select id="sel" class="input-block-level" ng-model="list_category" ng-options="obj.name for obj in list_categories" ng-change="DropDownChange()">
<option value="">Select</option>
</select>
<div ng-show="showdiv">
Hello
</div>
<div>
Angular
var app = angular.module('app', []);
$scope.showdiv=false;
function Ctrl($scope) {
$scope.list_categories = [{
id: 'id1',
name: 'A'
}, {
id: 'id2',
name: 'B'
}];
$scope.DropDownChange = function() {
$scope.showdiv = angular.equals($scope.list_category.name,'A');
}
}
Result - 'Hello' is displayed when 'A' is selected and hidden when 'B' is selected. But the problem is, if I select 'A' and then change my selection to 'Select', 'hello' is still displayed. I think its because 'select' is not one of my model data value the comparison is failing. Is there any other way to make this work without adding 'select' to my model data?
use like this
<div ng-show="list_category.name == 'A'">
var app = angular.module('app', []);
$scope.showdiv=false;
function Ctrl($scope) {
$scope.list_categories = [{
id: 'id1',
name: 'A'
}, {
id: 'id2',
name: 'B'
}];
$scope.DropDownChange = function() {
if($scope.list_category == null || $scope.list_category == "")
{
$scope.showdiv = false;
}
else{
$scope.showdiv = angular.equals($scope.list_category.name,'A');
}
}
}
Fiddle
My objective -
Directive dir2 replaces itself with directive dir1 which in turn replaces with input.
However during dir1 replacement by input I get parent is null exception in replaceWith function.
Fiddle for the same
var app = angular.module("myapp",[]);
function MyCtrlr($scope){
$scope.vars = {val:"xyz"};
}
app.directive("dir2", function($compile){
return {
restrict : 'E',
replace : true,
compile :function(el, attrs) {
var newhtml = '<dir1 field="' + attrs.field + '" />';
return function(scope, el, attrs) {
console.log('dir2 parent = ' + el.parent());
el.replaceWith($compile(newhtml)(scope));
}
}
}
});
app.directive("dir1", function($compile){
return {
restrict : 'E',
replace : true,
compile :function(el, attrs) {
return function(scope, el, attrs) {
console.log('dir1 parent = ' + el.parent());
console.log(scope.field);
el.replaceWith($compile('<input type="text" ng-model="' + attrs.field + '.val" />')(scope));
}
}
}
});
Basically you are getting the error message because the compilation process happens in two phases: compile and link.
As your directives are being compiled at the same time (1st phase),when the dir2 finishes its compilation the DOM element of the dir1 is not ready yet for manipulation.
So I've changed dir1 to use the link phase of the process (2nd phase).
Like this dir2 have the chance to be completed and created the DOM element(template) used by dir1
http://plnkr.co/edit/GrOPkNaxOxcXFDZfDwWh
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script>
var app = angular.module("myApp",[]);
function MyCtrlr($scope){
$scope.vars = {val:"xyz"};
}
app.directive("dir2", function($compile){
return {
restrict : 'E',
replace : true,
compile :function(el, attrs) {
var newhtml = '<dir1 field="' + attrs.field + '" />';
return function(scope, el, attrs) {
console.log('dir2 parent = ' + el.parent());
el.replaceWith($compile(newhtml)(scope));
}
}
}
});
app.directive("dir1", function($compile){
return {
restrict : 'E',
replace : true,
template: '<input type="text" ng-model="field" />',
scope: {
field: '='
},
link: function(scope, el, attrs) {
console.log('dir1 parent = ' + el.parent());
console.log(scope.field);
}
}
});
</script>
</head>
<body>
<div ng-app="myapp">
Testing
<div ng-controller = "MyCtrlr">
<span ng-bind="vars.val"></span>
<dir2 field="vars"></dir2>
</div>
</div>
</body>
</html>
Here is how you can accomplish what you want to do:
Wokring plunker
var app = angular.module('plunker', []);
function MyCtrlr($scope){
$scope.vars = {val:"xyz"};
}
app.directive("dir2", function($compile){
return {
restrict : 'E',
replace : true,
template: '<dir1></dir1>',
link: function(scope, el, attrs) {
}
};
});
app.directive("dir1", function($compile){
return {
restrict : 'E',
scope: {
field: '='
},
link: function(scope, el, attrs) {
scope.model = scope.field;
el.replaceWith($compile('<input type="text" ng-model="model.val" />')(scope));
}
};
});
This preserves the two way data binding, but is rather limited in its use. I am assuming that your use case is a simplification of your problem, otherwise a different approach might be simpler.
I am still working out the details on exactly what is going wrong in your fiddle, will post an edit when I figure that out.
Final Fiddle
Angularjs Chained Directives Replacing Elements
I started with an objective to develop a generic directive to render forms elements for Activiti engine tasks using Angularjs.
For which I developed a directive (say dir1) which based on certain properties of form element would render appropriate type html element (input (text, checkbox), select or span) replacing the dir1 element.
The controller that gathers Activiti form is emulated by the following code
function MyCtrlr($scope) {
$scope.v = [{value: 'init0'},
{value: 'init1'},
{value: 'init2'},
{value: 'init3'}
];
$scope.formVals = {
vals: [{
id: 'one',
type: 'string',
value: 'xyz'
}, {
id: 'two',
type: 'enum',
value: '2',
writable:true,
enumValues: [{
'id': 1,
'name': 'ek'
}, {
'id': 2,
'name': 'don'
}]
}, {
id: 'three',
type: 'enum',
value: 'abc',
writable:true,
enumValues: [{
'id': 3,
'name': 'tin'
}, {
'id': 4,
'name': 'chaar'
}]
}, {
id: 'four',
type: 'enum',
value: 'abc',
writable:true,
enumValues: [{
'id': 5,
'name': 'paach'
}, {
'id': 6,
'name': 'sahaa'
}]
},
{id:'five',
type:'string',
value:'test',
writable:true
}
]
};
//$scope.formVals.vals[0].varRef = $scope.v[0];
//$scope.formVals.vals[1].varRef = $scope.v[1];
$scope.formVals.vals[2].varRef = $scope.v[2];
$scope.formVals.vals[3].varRef = $scope.v[3];
$scope.verify = function () {
alert($scope.v[0].value + '...' + $scope.v[1].value + '...' + $scope.v[2].value + '...' + $scope.v[3].value);
};
}
And the directive dir1 as follows
app.directive('dir1', function ($compile) {
var getTemplate = function(fld, fvarnm, debug) {
value = ' value="' + fld.value + '"';
nm = ' name="' + fld.id + '"';
ngmodel = ' ng-model="' + fvarnm + '.varRef.value"';
disabled = fld.writable?'':' disabled=disabled';
switch(fld.type) {
case 'activitiUser':
case 'enum':
template = '<select '
+ nm + disabled
+ (fld.varRef != null?ngmodel:'');
template += '<option></option>';
for (e in fld.enumValues) {
selected = '';
ev = fld.enumValues[e];
if ((fld.varRef == null && (fld.value == ev.id)) || (fld.varRef != null) && (fld.varRef.value == ev.id))
selected = ' SELECTED ';
template += '<option value="' + ev.id + '"' + selected + '>' + ev.name + '</option>';
}
template += '</select>';
break;
case 'boolean':
template = '<input type="checkbox"'
+ nm + disabled
+ (fld.varRef != null?ngmodel:value)
+ (fld.value?' CHECKED':'')
+ '></input>';
break;
default:
template = '<input type="text"'
+ nm + disabled
+ (fld.varRef != null?ngmodel:value)
+ ' value-format="' + fld.type + ' '
+ fld.datePattern + '"'
+ '></input>';
}
if (fld.varRef != null && typeof(debug) != 'undefined' && debug.toLowerCase() == 'true') {
template = '<div>' + template
+ '<span ng-bind="' + fvarnm
+ '.varRef.value"></span>' + '</div>';
}
return template;
};
return {
restrict: 'E',
replace: true,
scope : {
field : '='
},
link : function(scope, element, attrs) {
html = getTemplate(scope.field, attrs.field, attrs.debug);
element.replaceWith($compile(html)(scope.$parent));
}
};
});
However when nuances of application on top of Activiti came in picture, I made a decision that I want to give developer an ability to user dir1 for his generic requirements and allow him to develop his own directive chained to dir1 to handle these nuances.
About nuances – based on properties of form element application developer would either go for generic rendering provided by dir1 or replace dir2 element with appropriate html element.
I added dir2 as follows -
app.directive('dir2', function ($compile) {
var getTemplate2 = function(scope, el, attrs) {
html2 = "<dir1 field='" + attrs.field + "'></dir1>";
if (scope.field.id == 'five') {
html2 = '<span style="font-weight:bold" ';
if (typeof(scope.field.varRef) != 'undefined' && scope.field.varRef) {
html2 += ' ng-bind="f.varRef.value" ';
} else {
html2 += ' ng-bind="f.value" ';
}
html2 += '></span> ';
}
return html2;
};
return {
restrict: 'E',
replace : true,
scope : {
field : '='
},
link: function (scope, el, attrs) {
var html2 = getTemplate2(scope, el, attrs);
el.replaceWith($compile(html2)(scope.$parent));
}
};
});
However I started getting null parent error in replaceWith call in dir1. After lot of disoriented thinking and console logging I realized that the moment html2 was getting compiled at el.replaceWith($compile(html2)(scope.$parent)) statement, dir1 link function was triggering whenever html2 was a dir1 element. At this point the dir1 element did not have any parentNode.
Therefore I came up with the following arrangement.
In gettemplate2 function html2 default value became html2 = "", i.e. passing parent attribute.
In dir1 link function I made the following changes
html = getTemplate(scope.field, attrs.field, attrs.debug);
scope.dir1el = $compile(html)(scope);
if (typeof(attrs.parent) == 'undefined') {
element.replaceWith(scope.dir1el);
}
thus preventing replacement in dir1. The complementary change in dir2 was
var html2 = getTemplate2(scope, el, attrs);
if (html2 == null) {
$compile("<dir1 parent='true' field='" + attrs.field + "'></dir1>")(scope.$parent);
ne = scope.$$nextSibling.dir1el;
} else {
ne = $compile(html2)(scope.$parent);
}
el.replaceWith(ne);
Since dir1 and dir2 are sibling directives, I had to access dir1 scope using $$nextSibling. Thus allowing me to replace element in dir2 with one generated by dir1 or dir2 as appropriate.
I also developed an alternate solution using attribute directive dir3, where dir3 would become attribute of dir1. Here dir1 scope becomes parent scope of dir3. And bespoke element in dir3 is replaces element replaces element created by dir1. Thus this solution involves double DOM replacement.